From 30ffbe9b8d49d8d8a2820f7b452ebc1d1531f298 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 23 Sep 2019 14:30:02 +0300 Subject: [core][android] Remove unaccent from platform interfaces The unaccent is used only within collator, thus, there is no need to have separate platform interface for it. --- next/platform/android/android.cmake | 1 - next/platform/linux/linux.cmake | 1 - next/platform/qt/qt.cmake | 2 -- platform/android/core-files.json | 4 +-- platform/android/src/text/collator.cpp | 12 +++----- platform/android/src/unaccent.cpp | 18 ------------ platform/default/src/mbgl/text/collator.cpp | 43 +++++++++++++++++++++++++++-- platform/default/src/mbgl/text/unaccent.cpp | 43 ----------------------------- platform/linux/config.cmake | 2 -- 9 files changed, 45 insertions(+), 81 deletions(-) delete mode 100644 platform/android/src/unaccent.cpp delete mode 100644 platform/default/src/mbgl/text/unaccent.cpp diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index 70683149d0..240d4ccfdf 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -195,7 +195,6 @@ target_sources( ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer_jni.hpp ${MBGL_ROOT}/platform/android/src/thread.cpp ${MBGL_ROOT}/platform/android/src/timer.cpp - ${MBGL_ROOT}/platform/android/src/unaccent.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_backend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_frontend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gl/headless_backend.cpp diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 9c8a3830b8..457ff441b8 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -31,7 +31,6 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/text/bidi.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/collator.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/local_glyph_rasterizer.cpp - ${MBGL_ROOT}/platform/default/src/mbgl/text/unaccent.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/async_task.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/format_number.cpp diff --git a/next/platform/qt/qt.cmake b/next/platform/qt/qt.cmake index a63b1cd4de..4d9275aaae 100644 --- a/next/platform/qt/qt.cmake +++ b/next/platform/qt/qt.cmake @@ -26,7 +26,6 @@ target_sources( ${MBGL_ROOT}/platform/default/include/mbgl/gfx/headless_backend.hpp ${MBGL_ROOT}/platform/default/include/mbgl/gfx/headless_frontend.hpp ${MBGL_ROOT}/platform/default/include/mbgl/gl/headless_backend.hpp - ${MBGL_ROOT}/platform/default/include/mbgl/text/unaccent.hpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_backend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_frontend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gl/headless_backend.cpp @@ -43,7 +42,6 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/online_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/collator.cpp - ${MBGL_ROOT}/platform/default/src/mbgl/text/unaccent.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp ${MBGL_ROOT}/platform/qt/src/async_task.cpp ${MBGL_ROOT}/platform/qt/src/async_task_impl.hpp diff --git a/platform/android/core-files.json b/platform/android/core-files.json index 362098dd9b..9d502bf33e 100644 --- a/platform/android/core-files.json +++ b/platform/android/core-files.json @@ -86,7 +86,6 @@ "platform/android/src/gl_functions.cpp", "platform/android/src/thread.cpp", "platform/android/src/timer.cpp", - "platform/android/src/unaccent.cpp", "platform/default/src/mbgl/gfx/headless_backend.cpp", "platform/default/src/mbgl/gfx/headless_frontend.cpp", "platform/default/src/mbgl/gl/headless_backend.cpp", @@ -103,8 +102,7 @@ "mbgl/gfx/headless_backend.hpp": "platform/default/include/mbgl/gfx/headless_backend.hpp", "mbgl/gfx/headless_frontend.hpp": "platform/default/include/mbgl/gfx/headless_frontend.hpp", "mbgl/gl/headless_backend.hpp": "platform/default/include/mbgl/gl/headless_backend.hpp", - "mbgl/map/map_snapshotter.hpp": "platform/default/include/mbgl/map/map_snapshotter.hpp", - "mbgl/text/unaccent.hpp": "platform/default/include/mbgl/text/unaccent.hpp" + "mbgl/map/map_snapshotter.hpp": "platform/default/include/mbgl/map/map_snapshotter.hpp" }, "private_headers": { "android_renderer_backend.hpp": "platform/android/src/android_renderer_backend.hpp", diff --git a/platform/android/src/text/collator.cpp b/platform/android/src/text/collator.cpp index acb4f36ee1..1cd6f3cab0 100644 --- a/platform/android/src/text/collator.cpp +++ b/platform/android/src/text/collator.cpp @@ -2,8 +2,6 @@ #include #include -#include - #include #include "../attach_env.hpp" @@ -144,12 +142,10 @@ public: // Because of the difference in locale-awareness, this means turning on case-sensitivity // can _potentially_ change compare results for strings that don't actually have any case // differences. - jni::Local jlhs = jni::Make(*env, useUnaccent ? - platform::unaccent(lhs) : - lhs); - jni::Local jrhs = jni::Make(*env, useUnaccent ? - platform::unaccent(rhs) : - rhs); + jni::Local jlhs = useUnaccent ? android::StringUtils::unaccent(*env, jni::Make(*env, lhs)) + : jni::Make(*env, lhs); + jni::Local jrhs = useUnaccent ? android::StringUtils::unaccent(*env, jni::Make(*env, rhs)) + : jni::Make(*env, rhs); jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); diff --git a/platform/android/src/unaccent.cpp b/platform/android/src/unaccent.cpp deleted file mode 100644 index 8da0ce4931..0000000000 --- a/platform/android/src/unaccent.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include -#include -#include "attach_env.hpp" -#include "text/collator_jni.hpp" -#include - -namespace mbgl { -namespace platform { - -std::string unaccent(const std::string& str) { - android::UniqueEnv env = android::AttachEnv(); - jni::Local input = jni::Make(*env, str); - jni::Local unaccented = android::StringUtils::unaccent(*env, input); - return jni::Make(*env, unaccented); -} - -} // namespace platform -} // namespace mbgl diff --git a/platform/default/src/mbgl/text/collator.cpp b/platform/default/src/mbgl/text/collator.cpp index 400fa4d94d..2d85b2d466 100644 --- a/platform/default/src/mbgl/text/collator.cpp +++ b/platform/default/src/mbgl/text/collator.cpp @@ -1,7 +1,10 @@ #include #include #include -#include +#include + +#include +#include /* The default implementation of Collator ignores locale. @@ -16,6 +19,40 @@ but would require bundling locale data. */ +namespace { +std::string unaccent(const std::string& str) +{ + std::stringstream output; + char const *itr = str.c_str(), *nitr; + char const *end = itr + str.length(); + char lo[5] = { 0 }; + + for (; itr < end; itr = nitr) + { + uint32_t code_point = 0; + char const* buf = nullptr; + + nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr); + if (buf != nullptr) + { + do + { + buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); + if (code_point == 0) break; + output.write(lo, nu_utf8_write(code_point, lo) - lo); + } + while (code_point != 0); + } + else + { + output.write(itr, nitr - itr); + } + } + + return output.str(); +} +} // namespace + namespace mbgl { namespace style { namespace expression { @@ -40,10 +77,10 @@ public: return nu_strcasecoll(lhs.c_str(), rhs.c_str(), nu_utf8_read, nu_utf8_read); } else if (caseSensitive && !diacriticSensitive) { - return nu_strcoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(), + return nu_strcoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), nu_utf8_read, nu_utf8_read); } else { - return nu_strcasecoll(platform::unaccent(lhs).c_str(), platform::unaccent(rhs).c_str(), + return nu_strcasecoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), nu_utf8_read, nu_utf8_read); } } diff --git a/platform/default/src/mbgl/text/unaccent.cpp b/platform/default/src/mbgl/text/unaccent.cpp deleted file mode 100644 index 37b9a0d9ca..0000000000 --- a/platform/default/src/mbgl/text/unaccent.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include -#include - -namespace mbgl { namespace platform { - -std::string unaccent(const std::string& str) -{ - std::stringstream output; - char const *itr = str.c_str(), *nitr; - char const *end = itr + str.length(); - char lo[5] = { 0 }; - - for (; itr < end; itr = nitr) - { - uint32_t code_point = 0; - char const* buf = nullptr; - - nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr); - if (buf != nullptr) - { - do - { - buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); - if (code_point == 0) break; - output.write(lo, nu_utf8_write(code_point, lo) - lo); - } - while (code_point != 0); - } - else - { - output.write(itr, nitr - itr); - } - } - - return output.str(); -} - -} // namespace platform -} // namespace mbgl diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 55e6e3c192..3a0fd91d36 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -54,8 +54,6 @@ macro(mbgl_platform_core) PRIVATE platform/default/src/mbgl/layermanager/layer_manager.cpp PRIVATE platform/default/src/mbgl/text/local_glyph_rasterizer.cpp PRIVATE platform/default/src/mbgl/util/thread_local.cpp - PRIVATE platform/default/src/mbgl/text/unaccent.cpp - PRIVATE platform/default/include/mbgl/text/unaccent.hpp PRIVATE platform/default/src/mbgl/util/utf.cpp PRIVATE platform/default/src/mbgl/util/format_number.cpp -- cgit v1.2.1 From 9c8295c6a64b6f5b2c9b67fd01633a156481a3c8 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 23 Sep 2019 15:42:06 +0300 Subject: [core][android][darwin] Move platform specific Collator impls from expression Platform specific Collator implementations should not be part of an expression APIs. --- include/mbgl/i18n/collator.hpp | 24 +++ include/mbgl/style/expression/collator.hpp | 6 +- next/CMakeLists.txt | 1 + next/platform/android/android.cmake | 4 +- next/platform/linux/linux.cmake | 2 +- next/platform/qt/qt.cmake | 2 +- platform/android/core-files.json | 4 +- platform/android/src/i18n/collator.cpp | 194 +++++++++++++++++++++++ platform/android/src/i18n/collator_jni.hpp | 62 ++++++++ platform/android/src/jni_native.cpp | 4 +- platform/android/src/text/collator.cpp | 195 ------------------------ platform/android/src/text/collator_jni.hpp | 64 -------- platform/android/src/text/format_number_jni.hpp | 2 +- platform/darwin/src/collator.mm | 9 +- platform/default/src/mbgl/i18n/collator.cpp | 101 ++++++++++++ platform/default/src/mbgl/text/collator.cpp | 116 -------------- platform/linux/config.cmake | 2 +- src/core-files.json | 1 + src/mbgl/style/expression/collator.cpp | 24 +++ 19 files changed, 422 insertions(+), 395 deletions(-) create mode 100644 include/mbgl/i18n/collator.hpp create mode 100644 platform/android/src/i18n/collator.cpp create mode 100644 platform/android/src/i18n/collator_jni.hpp mode change 100755 => 100644 platform/android/src/jni_native.cpp delete mode 100644 platform/android/src/text/collator.cpp delete mode 100644 platform/android/src/text/collator_jni.hpp create mode 100644 platform/default/src/mbgl/i18n/collator.cpp delete mode 100644 platform/default/src/mbgl/text/collator.cpp create mode 100644 src/mbgl/style/expression/collator.cpp diff --git a/include/mbgl/i18n/collator.hpp b/include/mbgl/i18n/collator.hpp new file mode 100644 index 0000000000..9db1f804aa --- /dev/null +++ b/include/mbgl/i18n/collator.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include +#include + +namespace mbgl { +namespace platform { + +class Collator { +public: + explicit Collator(bool caseSensitive, bool diacriticSensitive, optional locale = nullopt); + int compare(const std::string& lhs, const std::string& rhs) const; + std::string resolvedLocale() const; + bool operator==(const Collator& other) const; + +private: + class Impl; + std::shared_ptr impl; +}; + +} // namespace platform +} // namespace mbgl diff --git a/include/mbgl/style/expression/collator.hpp b/include/mbgl/style/expression/collator.hpp index 2a79e55556..51ba426fad 100644 --- a/include/mbgl/style/expression/collator.hpp +++ b/include/mbgl/style/expression/collator.hpp @@ -1,10 +1,9 @@ #pragma once -#include +#include #include #include -#include namespace mbgl { namespace style { @@ -20,8 +19,7 @@ public: std::string resolvedLocale() const; private: - class Impl; - std::shared_ptr impl; + platform::Collator collator; }; } // namespace expression diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index dae8ce09a1..bc15f04420 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -596,6 +596,7 @@ add_library( ${MBGL_ROOT}/src/mbgl/style/expression/check_subtype.cpp ${MBGL_ROOT}/src/mbgl/style/expression/coalesce.cpp ${MBGL_ROOT}/src/mbgl/style/expression/coercion.cpp + ${MBGL_ROOT}/src/mbgl/style/expression/collator.cpp ${MBGL_ROOT}/src/mbgl/style/expression/collator_expression.cpp ${MBGL_ROOT}/src/mbgl/style/expression/comparison.cpp ${MBGL_ROOT}/src/mbgl/style/expression/compound_expression.cpp diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index 240d4ccfdf..edc74576dc 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -187,8 +187,8 @@ target_sources( ${MBGL_ROOT}/platform/android/src/style/transition_options.hpp ${MBGL_ROOT}/platform/android/src/style/value.cpp ${MBGL_ROOT}/platform/android/src/style/value.hpp - ${MBGL_ROOT}/platform/android/src/text/collator.cpp - ${MBGL_ROOT}/platform/android/src/text/collator_jni.hpp + ${MBGL_ROOT}/platform/android/src/i18n/collator.cpp + ${MBGL_ROOT}/platform/android/src/i18n/collator_jni.hpp ${MBGL_ROOT}/platform/android/src/text/format_number.cpp ${MBGL_ROOT}/platform/android/src/text/format_number_jni.hpp ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer.cpp diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 457ff441b8..993d3512e3 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -29,7 +29,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/online_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/bidi.cpp - ${MBGL_ROOT}/platform/default/src/mbgl/text/collator.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/i18n/collator.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/local_glyph_rasterizer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/async_task.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp diff --git a/next/platform/qt/qt.cmake b/next/platform/qt/qt.cmake index 4d9275aaae..59aa00788f 100644 --- a/next/platform/qt/qt.cmake +++ b/next/platform/qt/qt.cmake @@ -29,6 +29,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_backend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_frontend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gl/headless_backend.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/i18n/collator.cpp ${MBGL_ROOT}/platform/default/src/mbgl/layermanager/layer_manager.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/asset_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/default_file_source.cpp @@ -41,7 +42,6 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/offline_download.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/online_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp - ${MBGL_ROOT}/platform/default/src/mbgl/text/collator.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp ${MBGL_ROOT}/platform/qt/src/async_task.cpp ${MBGL_ROOT}/platform/qt/src/async_task_impl.hpp diff --git a/platform/android/core-files.json b/platform/android/core-files.json index 9d502bf33e..4057b21000 100644 --- a/platform/android/core-files.json +++ b/platform/android/core-files.json @@ -80,7 +80,7 @@ "platform/android/src/style/sources/vector_source.cpp", "platform/android/src/style/transition_options.cpp", "platform/android/src/style/value.cpp", - "platform/android/src/text/collator.cpp", + "platform/android/src/i18n/collator.cpp", "platform/android/src/text/local_glyph_rasterizer.cpp", "platform/android/src/text/format_number.cpp", "platform/android/src/gl_functions.cpp", @@ -185,7 +185,7 @@ "style/sources/vector_source.hpp": "platform/android/src/style/sources/vector_source.hpp", "style/transition_options.hpp": "platform/android/src/style/transition_options.hpp", "style/value.hpp": "platform/android/src/style/value.hpp", - "text/collator_jni.hpp": "platform/android/src/text/collator_jni.hpp", + "text/collator_jni.hpp": "platform/android/src/i18n/collator_jni.hpp", "text/local_glyph_rasterizer_jni.hpp": "platform/android/src/text/local_glyph_rasterizer_jni.hpp" } } diff --git a/platform/android/src/i18n/collator.cpp b/platform/android/src/i18n/collator.cpp new file mode 100644 index 0000000000..b3dd8e21b3 --- /dev/null +++ b/platform/android/src/i18n/collator.cpp @@ -0,0 +1,194 @@ +#include +#include + +#include + +#include "../attach_env.hpp" +#include "collator_jni.hpp" + +namespace mbgl { +namespace android { + +void Collator::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setStrength"); + collator.Call(env, method, strength); +} + +jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "compare"); + return collator.Call(env, method, lhs, rhs); +} + +void StringUtils::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod(env, "unaccent"); + return javaClass.Call(env, method, value); +} + +void Locale::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +/* +We would prefer to use for/toLanguageTag, but they're only available in API level 21+ + +jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { + using Signature = jni::Object(jni::String); + auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); + return javaClass.Call(env, method, languageTag); +} + +jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { + using Signature = jni::String(); + auto static method = javaClass.GetMethod(env, "toLanguageTag"); + return locale.Call(env, method); +} +*/ + +jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getLanguage"); + return locale.Call(env, method); +} + +jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "getCountry"); + return locale.Call(env, method); +} + +jni::Local> Locale::getDefault(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); + return javaClass.Call(env, method); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language); +} + +jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { + static auto& javaClass = jni::Class::Singleton(env); + static auto constructor = javaClass.GetConstructor(env); + return javaClass.New(env, constructor, language, region); +} + +} // namespace android + +namespace platform { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) + : caseSensitive(caseSensitive_) + , diacriticSensitive(diacriticSensitive_) + , env(android::AttachEnv()) + { + LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, + android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, + android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); + if (!diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); + } else if (diacriticSensitive && !caseSensitive) { + android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); + } else if (caseSensitive) { + // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator + // and a fallback implementation of diacritic-insensitivity. + android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); + } + } + + bool operator==(const Impl& other) const { + return caseSensitive == other.caseSensitive && + diacriticSensitive == other.diacriticSensitive && + resolvedLocale() == other.resolvedLocale(); + } + + int compare(const std::string& lhs, const std::string& rhs) const { + bool useUnaccent = !diacriticSensitive && caseSensitive; + // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation + // order, so we have to compromise here. We use Android's case-sensitive Collator + // against strings that have been "unaccented" using non-locale-aware nunicode logic. + // Because of the difference in locale-awareness, this means turning on case-sensitivity + // can _potentially_ change compare results for strings that don't actually have any case + // differences. + jni::Local jlhs = useUnaccent + ? android::StringUtils::unaccent(*env, jni::Make(*env, lhs)) + : jni::Make(*env, lhs); + jni::Local jrhs = useUnaccent + ? android::StringUtils::unaccent(*env, jni::Make(*env, rhs)) + : jni::Make(*env, rhs); + + jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); + + return result; + } + + std::string resolvedLocale() const { + std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); + std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); + + optional resultLanguage; + if (!language.empty()) resultLanguage = language; + optional resultRegion; + if (!region.empty()) resultRegion = region; + + return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); + } + +private: + bool caseSensitive; + bool diacriticSensitive; + + android::UniqueEnv env; + jni::Global> collator; + jni::Global> locale; +}; + + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) + : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) +{} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/android/src/i18n/collator_jni.hpp b/platform/android/src/i18n/collator_jni.hpp new file mode 100644 index 0000000000..612f9b49f3 --- /dev/null +++ b/platform/android/src/i18n/collator_jni.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include + +/* + android::Collator and android::Locale are + the JNI wrappers of + java/text/Collator and java/util/Locale + + mbgl::Collator is the portable interface + Both implementations are in collator.cpp + */ + +namespace mbgl { +namespace android { + +class Locale { +public: + static constexpr auto Name() { return "java/util/Locale"; }; + + /* Requires API level 21+ in order to support script/variant + static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); + static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); + */ + static jni::Local> getDefault(jni::JNIEnv&); + static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); + static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); + + static jni::Local> New(jni::JNIEnv&, const jni::String&); + static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +class Collator { +public: + static constexpr auto Name() { return "java/text/Collator"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + + static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); + + static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + + +class StringUtils { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; + + static jni::Local unaccent(jni::JNIEnv&, const jni::String&); + + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/jni_native.cpp b/platform/android/src/jni_native.cpp old mode 100755 new mode 100644 index df96ba9759..966dc6a007 --- a/platform/android/src/jni_native.cpp +++ b/platform/android/src/jni_native.cpp @@ -50,10 +50,10 @@ #include "snapshotter/map_snapshotter.hpp" #include "snapshotter/map_snapshot.hpp" #endif -#include "text/collator_jni.hpp" +#include "i18n/collator_jni.hpp" +#include "logger.hpp" #include "text/local_glyph_rasterizer_jni.hpp" #include "text/format_number_jni.hpp" -#include "logger.hpp" namespace mbgl { namespace android { diff --git a/platform/android/src/text/collator.cpp b/platform/android/src/text/collator.cpp deleted file mode 100644 index 1cd6f3cab0..0000000000 --- a/platform/android/src/text/collator.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include -#include - -#include - -#include "../attach_env.hpp" -#include "collator_jni.hpp" - -namespace mbgl { -namespace android { - -void Collator::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> Collator::getInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); - return javaClass.Call(env, method, locale); -} - -void Collator::setStrength(jni::JNIEnv& env, const jni::Object& collator, jni::jint strength) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setStrength"); - collator.Call(env, method, strength); -} - -jni::jint Collator::compare(jni::JNIEnv& env, const jni::Object& collator, const jni::String& lhs, const jni::String& rhs) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "compare"); - return collator.Call(env, method, lhs, rhs); -} - -void StringUtils::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local StringUtils::unaccent(jni::JNIEnv& env, const jni::String& value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod(env, "unaccent"); - return javaClass.Call(env, method, value); -} - -void Locale::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -/* -We would prefer to use for/toLanguageTag, but they're only available in API level 21+ - -jni::Object Locale::forLanguageTag(jni::JNIEnv& env, jni::String languageTag) { - using Signature = jni::Object(jni::String); - auto method = javaClass.GetStaticMethod(env, "forLanguageTag"); - return javaClass.Call(env, method, languageTag); -} - -jni::String Locale::toLanguageTag(jni::JNIEnv& env, jni::Object locale) { - using Signature = jni::String(); - auto static method = javaClass.GetMethod(env, "toLanguageTag"); - return locale.Call(env, method); -} -*/ - -jni::Local Locale::getLanguage(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "getLanguage"); - return locale.Call(env, method); -} - -jni::Local Locale::getCountry(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "getCountry"); - return locale.Call(env, method); -} - -jni::Local> Locale::getDefault(jni::JNIEnv& env) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod ()>(env, "getDefault"); - return javaClass.Call(env, method); -} - -jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, language); -} - -jni::Local> Locale::New(jni::JNIEnv& env, const jni::String& language, const jni::String& region) { - static auto& javaClass = jni::Class::Singleton(env); - static auto constructor = javaClass.GetConstructor(env); - return javaClass.New(env, constructor, language, region); -} - -} // namespace android - -namespace style { -namespace expression { - -class Collator::Impl { -public: - Impl(bool caseSensitive_, bool diacriticSensitive_, optional locale_) - : caseSensitive(caseSensitive_) - , diacriticSensitive(diacriticSensitive_) - , env(android::AttachEnv()) - { - LanguageTag languageTag = locale_ ? LanguageTag::fromBCP47(*locale_) : LanguageTag(); - if (!languageTag.language) { - locale = jni::NewGlobal(*env, - android::Locale::getDefault(*env)); - } else if (!languageTag.region) { - locale = jni::NewGlobal(*env, - android::Locale::New(*env, jni::Make(*env, *languageTag.language))); - } else { - locale = jni::NewGlobal(*env, - android::Locale::New(*env, jni::Make(*env, *languageTag.language), - jni::Make(*env, *languageTag.region))); - } - collator = jni::NewGlobal(*env, android::Collator::getInstance(*env, locale)); - if (!diacriticSensitive && !caseSensitive) { - android::Collator::setStrength(*env, collator, 0 /*PRIMARY*/); - } else if (diacriticSensitive && !caseSensitive) { - android::Collator::setStrength(*env, collator, 1 /*SECONDARY*/); - } else if (caseSensitive) { - // If we're case-sensitive and diacritic-sensitive, we use a case-sensitive collator - // and a fallback implementation of diacritic-insensitivity. - android::Collator::setStrength(*env, collator, 2 /*TERTIARY*/); - } - } - - bool operator==(const Impl& other) const { - return caseSensitive == other.caseSensitive && - diacriticSensitive == other.diacriticSensitive && - resolvedLocale() == other.resolvedLocale(); - } - - int compare(const std::string& lhs, const std::string& rhs) const { - bool useUnaccent = !diacriticSensitive && caseSensitive; - // java.text.Collator doesn't support a diacritic-insensitive/case-sensitive collation - // order, so we have to compromise here. We use Android's case-sensitive Collator - // against strings that have been "unaccented" using non-locale-aware nunicode logic. - // Because of the difference in locale-awareness, this means turning on case-sensitivity - // can _potentially_ change compare results for strings that don't actually have any case - // differences. - jni::Local jlhs = useUnaccent ? android::StringUtils::unaccent(*env, jni::Make(*env, lhs)) - : jni::Make(*env, lhs); - jni::Local jrhs = useUnaccent ? android::StringUtils::unaccent(*env, jni::Make(*env, rhs)) - : jni::Make(*env, rhs); - - jni::jint result = android::Collator::compare(*env, collator, jlhs, jrhs); - - return result; - } - - std::string resolvedLocale() const { - std::string language = jni::Make(*env, android::Locale::getLanguage(*env, locale)); - std::string region = jni::Make(*env, android::Locale::getCountry(*env, locale)); - - optional resultLanguage; - if (!language.empty()) resultLanguage = language; - optional resultRegion; - if (!region.empty()) resultRegion = region; - - return LanguageTag(resultLanguage, {}, resultRegion).toBCP47(); - } - -private: - bool caseSensitive; - bool diacriticSensitive; - - android::UniqueEnv env; - jni::Global> collator; - jni::Global> locale; -}; - - -Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) - : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) -{} - -bool Collator::operator==(const Collator& other) const { - return *impl == *(other.impl); -} - -int Collator::compare(const std::string& lhs, const std::string& rhs) const { - return impl->compare(lhs, rhs); -} - -std::string Collator::resolvedLocale() const { - return impl->resolvedLocale(); -} - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/platform/android/src/text/collator_jni.hpp b/platform/android/src/text/collator_jni.hpp deleted file mode 100644 index dd3f845662..0000000000 --- a/platform/android/src/text/collator_jni.hpp +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include - -#include - -/* - android::Collator and android::Locale are - the JNI wrappers of - java/text/Collator and java/util/Locale - - mbgl::Collator is the portable interface - Both implementations are in collator.cpp - */ - -namespace mbgl { -namespace android { - -class Locale { -public: - static constexpr auto Name() { return "java/util/Locale"; }; - - /* Requires API level 21+ in order to support script/variant - static jni::Object forLanguageTag(jni::JNIEnv&, jni::String); - static jni::String toLanguageTag(jni::JNIEnv&, jni::Object); - */ - static jni::Local> getDefault(jni::JNIEnv&); - static jni::Local getLanguage(jni::JNIEnv&, const jni::Object&); - static jni::Local getCountry(jni::JNIEnv&, const jni::Object&); - - static jni::Local> New(jni::JNIEnv&, const jni::String&); - static jni::Local> New(jni::JNIEnv&, const jni::String&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - -class Collator { -public: - static constexpr auto Name() { return "java/text/Collator"; }; - - static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); - - static void setStrength(jni::JNIEnv&, const jni::Object&, jni::jint); - - static jni::jint compare(jni::JNIEnv&, const jni::Object&, const jni::String&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - - -class StringUtils { -public: - static constexpr auto Name() { return "com/mapbox/mapboxsdk/utils/StringUtils"; }; - - static jni::Local unaccent(jni::JNIEnv&, const jni::String&); - - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/text/format_number_jni.hpp b/platform/android/src/text/format_number_jni.hpp index 1720038925..1b63012c6e 100644 --- a/platform/android/src/text/format_number_jni.hpp +++ b/platform/android/src/text/format_number_jni.hpp @@ -2,7 +2,7 @@ #include -#include "collator_jni.hpp" +#include "../i18n/collator_jni.hpp" /* android::NumberFormat is the JNI wrapper diff --git a/platform/darwin/src/collator.mm b/platform/darwin/src/collator.mm index fe2b46ffa7..0f010c1df8 100644 --- a/platform/darwin/src/collator.mm +++ b/platform/darwin/src/collator.mm @@ -1,12 +1,11 @@ -#include +#include #include #import namespace mbgl { -namespace style { -namespace expression { +namespace platform { class Collator::Impl { public: @@ -48,7 +47,6 @@ private: NSLocale* locale; }; - Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) {} @@ -65,6 +63,5 @@ std::string Collator::resolvedLocale() const { return impl->resolvedLocale(); } -} // namespace expression -} // namespace style +} // namespace platform } // namespace mbgl diff --git a/platform/default/src/mbgl/i18n/collator.cpp b/platform/default/src/mbgl/i18n/collator.cpp new file mode 100644 index 0000000000..f46accff8a --- /dev/null +++ b/platform/default/src/mbgl/i18n/collator.cpp @@ -0,0 +1,101 @@ +#include +#include +#include + +#include +#include + +/* + The default implementation of Collator ignores locale. + Case sensitivity and collation order are based on + Default Unicode Collation Element Table (DUCET). + + Diacritic-insensitivity is implemented with nunicode's + non-standard "unaccent" functionality, which is tailored + to European languages. + + It would be possible to implement locale awareness using ICU, + but would require bundling locale data. +*/ + +namespace { +std::string unaccent(const std::string& str) { + std::stringstream output; + char const *itr = str.c_str(), *nitr; + char const* end = itr + str.length(); + char lo[5] = {0}; + + for (; itr < end; itr = nitr) { + uint32_t code_point = 0; + char const* buf = nullptr; + + nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr); + if (buf != nullptr) { + do { + buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); + if (code_point == 0) break; + output.write(lo, nu_utf8_write(code_point, lo) - lo); + } while (code_point != 0); + } else { + output.write(itr, nitr - itr); + } + } + + return output.str(); +} +} // namespace + +namespace mbgl { +namespace platform { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional) + : caseSensitive(caseSensitive_) + , diacriticSensitive(diacriticSensitive_) + {} + + bool operator==(const Impl& other) const { + return caseSensitive == other.caseSensitive && diacriticSensitive == other.diacriticSensitive; + } + + int compare(const std::string& lhs, const std::string& rhs) const { + if (caseSensitive && diacriticSensitive) { + return nu_strcoll(lhs.c_str(), rhs.c_str(), + nu_utf8_read, nu_utf8_read); + } else if (!caseSensitive && diacriticSensitive) { + return nu_strcasecoll(lhs.c_str(), rhs.c_str(), + nu_utf8_read, nu_utf8_read); + } else if (caseSensitive && !diacriticSensitive) { + return nu_strcoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), nu_utf8_read, nu_utf8_read); + } else { + return nu_strcasecoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), nu_utf8_read, nu_utf8_read); + } + } + + std::string resolvedLocale() const { + return ""; + } + +private: + bool caseSensitive; + bool diacriticSensitive; +}; + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale) + : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale))) {} + +} // namespace platform +} // namespace mbgl diff --git a/platform/default/src/mbgl/text/collator.cpp b/platform/default/src/mbgl/text/collator.cpp deleted file mode 100644 index 2d85b2d466..0000000000 --- a/platform/default/src/mbgl/text/collator.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -/* - The default implementation of Collator ignores locale. - Case sensitivity and collation order are based on - Default Unicode Collation Element Table (DUCET). - - Diacritic-insensitivity is implemented with nunicode's - non-standard "unaccent" functionality, which is tailored - to European languages. - - It would be possible to implement locale awareness using ICU, - but would require bundling locale data. -*/ - -namespace { -std::string unaccent(const std::string& str) -{ - std::stringstream output; - char const *itr = str.c_str(), *nitr; - char const *end = itr + str.length(); - char lo[5] = { 0 }; - - for (; itr < end; itr = nitr) - { - uint32_t code_point = 0; - char const* buf = nullptr; - - nitr = _nu_tounaccent(itr, end, nu_utf8_read, &code_point, &buf, nullptr); - if (buf != nullptr) - { - do - { - buf = NU_CASEMAP_DECODING_FUNCTION(buf, &code_point); - if (code_point == 0) break; - output.write(lo, nu_utf8_write(code_point, lo) - lo); - } - while (code_point != 0); - } - else - { - output.write(itr, nitr - itr); - } - } - - return output.str(); -} -} // namespace - -namespace mbgl { -namespace style { -namespace expression { - -class Collator::Impl { -public: - Impl(bool caseSensitive_, bool diacriticSensitive_, optional) - : caseSensitive(caseSensitive_) - , diacriticSensitive(diacriticSensitive_) - {} - - bool operator==(const Impl& other) const { - return caseSensitive == other.caseSensitive && - diacriticSensitive == other.diacriticSensitive; - } - - int compare(const std::string& lhs, const std::string& rhs) const { - if (caseSensitive && diacriticSensitive) { - return nu_strcoll(lhs.c_str(), rhs.c_str(), - nu_utf8_read, nu_utf8_read); - } else if (!caseSensitive && diacriticSensitive) { - return nu_strcasecoll(lhs.c_str(), rhs.c_str(), - nu_utf8_read, nu_utf8_read); - } else if (caseSensitive && !diacriticSensitive) { - return nu_strcoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), - nu_utf8_read, nu_utf8_read); - } else { - return nu_strcasecoll(unaccent(lhs).c_str(), unaccent(rhs).c_str(), - nu_utf8_read, nu_utf8_read); - } - } - - std::string resolvedLocale() const { - return ""; - } -private: - bool caseSensitive; - bool diacriticSensitive; -}; - - -Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) - : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) -{} - -bool Collator::operator==(const Collator& other) const { - return *impl == *(other.impl); -} - -int Collator::compare(const std::string& lhs, const std::string& rhs) const { - return impl->compare(lhs, rhs); -} - -std::string Collator::resolvedLocale() const { - return impl->resolvedLocale(); -} - - -} // namespace expression -} // namespace style -} // namespace mbgl diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 3a0fd91d36..01c46c9fcb 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -50,7 +50,7 @@ macro(mbgl_platform_core) PRIVATE platform/default/src/mbgl/util/string_stdlib.cpp PRIVATE platform/default/src/mbgl/util/thread.cpp PRIVATE platform/default/src/mbgl/text/bidi.cpp - PRIVATE platform/default/src/mbgl/text/collator.cpp + PRIVATE platform/default/src/mbgl/i18n/collator.cpp PRIVATE platform/default/src/mbgl/layermanager/layer_manager.cpp PRIVATE platform/default/src/mbgl/text/local_glyph_rasterizer.cpp PRIVATE platform/default/src/mbgl/util/thread_local.cpp diff --git a/src/core-files.json b/src/core-files.json index d881e6259d..2f609e92ec 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -178,6 +178,7 @@ "src/mbgl/style/expression/check_subtype.cpp", "src/mbgl/style/expression/coalesce.cpp", "src/mbgl/style/expression/coercion.cpp", + "src/mbgl/style/expression/collator.cpp", "src/mbgl/style/expression/collator_expression.cpp", "src/mbgl/style/expression/comparison.cpp", "src/mbgl/style/expression/compound_expression.cpp", diff --git a/src/mbgl/style/expression/collator.cpp b/src/mbgl/style/expression/collator.cpp new file mode 100644 index 0000000000..185d713150 --- /dev/null +++ b/src/mbgl/style/expression/collator.cpp @@ -0,0 +1,24 @@ +#include + +namespace mbgl { +namespace style { +namespace expression { + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale) + : collator(platform::Collator(caseSensitive, diacriticSensitive, std::move(locale))) {} + +bool Collator::operator==(const Collator& other) const { + return collator == other.collator; +} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return collator.compare(lhs, rhs); +} + +std::string Collator::resolvedLocale() const { + return collator.resolvedLocale(); +} + +} // namespace expression +} // namespace style +} // namespace mbgl -- cgit v1.2.1 From e5cdc4ecf362dadf2da148a22cf97aaf3c9c4ecf Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 23 Sep 2019 17:22:38 +0300 Subject: [core][android][darwin] Move number format to i18n --- include/mbgl/i18n/number_format.hpp | 15 +++++ include/mbgl/util/platform.hpp | 3 - next/platform/android/android.cmake | 8 +-- next/platform/ios/ios.cmake | 1 + next/platform/linux/linux.cmake | 4 +- next/platform/macos/macos.cmake | 1 + next/platform/qt/qt.cmake | 2 +- platform/android/core-files.json | 7 +- platform/android/src/i18n/number_format.cpp | 80 +++++++++++++++++++++++ platform/android/src/i18n/number_format_jni.hpp | 29 +++++++++ platform/android/src/jni_native.cpp | 2 +- platform/android/src/text/format_number.cpp | 81 ------------------------ platform/android/src/text/format_number_jni.hpp | 29 --------- platform/darwin/src/number_format.mm | 36 +++++++++++ platform/darwin/src/string_nsstring.mm | 31 +-------- platform/default/src/mbgl/i18n/format_number.cpp | 39 ++++++++++++ platform/default/src/mbgl/i18n/number_format.cpp | 41 ++++++++++++ platform/default/src/mbgl/util/format_number.cpp | 39 ------------ platform/ios/core-files.json | 1 + platform/linux/config.cmake | 12 ++-- platform/macos/core-files.json | 1 + platform/qt/src/format_number.cpp | 26 -------- platform/qt/src/number_format.cpp | 26 ++++++++ src/core-files.json | 2 + src/mbgl/style/expression/number_format.cpp | 4 +- 25 files changed, 294 insertions(+), 226 deletions(-) create mode 100644 include/mbgl/i18n/number_format.hpp create mode 100644 platform/android/src/i18n/number_format.cpp create mode 100644 platform/android/src/i18n/number_format_jni.hpp delete mode 100644 platform/android/src/text/format_number.cpp delete mode 100644 platform/android/src/text/format_number_jni.hpp create mode 100644 platform/darwin/src/number_format.mm create mode 100644 platform/default/src/mbgl/i18n/format_number.cpp create mode 100644 platform/default/src/mbgl/i18n/number_format.cpp delete mode 100644 platform/default/src/mbgl/util/format_number.cpp delete mode 100644 platform/qt/src/format_number.cpp create mode 100644 platform/qt/src/number_format.cpp diff --git a/include/mbgl/i18n/number_format.hpp b/include/mbgl/i18n/number_format.hpp new file mode 100644 index 0000000000..cb1e94c7bd --- /dev/null +++ b/include/mbgl/i18n/number_format.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace mbgl { +namespace platform { + +std::string formatNumber(double number, + const std::string& localeId, + const std::string& currency, + uint8_t minFractionDigits, + uint8_t maxFractionDigits); + +} // namespace platform +} // namespace mbgl diff --git a/include/mbgl/util/platform.hpp b/include/mbgl/util/platform.hpp index 2e11e5f186..3544659740 100644 --- a/include/mbgl/util/platform.hpp +++ b/include/mbgl/util/platform.hpp @@ -16,9 +16,6 @@ std::string lowercase(const std::string &string); // Gets the name of the current thread. std::string getCurrentThreadName(); -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits); - // Set the name of the current thread, truncated at 15. void setCurrentThreadName(const std::string& name); diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index edc74576dc..507c1baef0 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -85,6 +85,10 @@ target_sources( ${MBGL_ROOT}/platform/android/src/gson/json_primitive.cpp ${MBGL_ROOT}/platform/android/src/gson/json_primitive.hpp ${MBGL_ROOT}/platform/android/src/http_file_source.cpp + ${MBGL_ROOT}/platform/android/src/i18n/collator.cpp + ${MBGL_ROOT}/platform/android/src/i18n/collator_jni.hpp + ${MBGL_ROOT}/platform/android/src/i18n/number_format.cpp + ${MBGL_ROOT}/platform/android/src/i18n/number_format_jni.hpp ${MBGL_ROOT}/platform/android/src/image.cpp ${MBGL_ROOT}/platform/android/src/java/util.cpp ${MBGL_ROOT}/platform/android/src/java/util.hpp @@ -187,10 +191,6 @@ target_sources( ${MBGL_ROOT}/platform/android/src/style/transition_options.hpp ${MBGL_ROOT}/platform/android/src/style/value.cpp ${MBGL_ROOT}/platform/android/src/style/value.hpp - ${MBGL_ROOT}/platform/android/src/i18n/collator.cpp - ${MBGL_ROOT}/platform/android/src/i18n/collator_jni.hpp - ${MBGL_ROOT}/platform/android/src/text/format_number.cpp - ${MBGL_ROOT}/platform/android/src/text/format_number_jni.hpp ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer.cpp ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer_jni.hpp ${MBGL_ROOT}/platform/android/src/thread.cpp diff --git a/next/platform/ios/ios.cmake b/next/platform/ios/ios.cmake index 507150fc9a..7a729d996a 100644 --- a/next/platform/ios/ios.cmake +++ b/next/platform/ios/ios.cmake @@ -15,6 +15,7 @@ target_sources( ${MBGL_ROOT}/platform/darwin/src/local_glyph_rasterizer.mm ${MBGL_ROOT}/platform/darwin/src/logging_nslog.mm ${MBGL_ROOT}/platform/darwin/src/nsthread.mm + ${MBGL_ROOT}/platform/darwin/src/number_format.mm ${MBGL_ROOT}/platform/darwin/src/reachability.m ${MBGL_ROOT}/platform/darwin/src/run_loop.cpp ${MBGL_ROOT}/platform/darwin/src/string_nsstring.mm diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 993d3512e3..18531a2856 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -15,6 +15,8 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_backend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_frontend.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gl/headless_backend.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/i18n/collator.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/i18n/number_format.cpp ${MBGL_ROOT}/platform/default/src/mbgl/layermanager/layer_manager.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/asset_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/default_file_source.cpp @@ -29,11 +31,9 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/online_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/bidi.cpp - ${MBGL_ROOT}/platform/default/src/mbgl/i18n/collator.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/local_glyph_rasterizer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/async_task.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp - ${MBGL_ROOT}/platform/default/src/mbgl/util/format_number.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/image.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/jpeg_reader.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/logging_stderr.cpp diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index d0aad9c3dc..a0dcb9a829 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -83,6 +83,7 @@ target_sources( ${MBGL_ROOT}/platform/darwin/src/local_glyph_rasterizer.mm ${MBGL_ROOT}/platform/darwin/src/logging_nslog.mm ${MBGL_ROOT}/platform/darwin/src/nsthread.mm + ${MBGL_ROOT}/platform/darwin/src/number_format.mm ${MBGL_ROOT}/platform/darwin/src/reachability.m ${MBGL_ROOT}/platform/darwin/src/run_loop.cpp ${MBGL_ROOT}/platform/darwin/src/string_nsstring.mm diff --git a/next/platform/qt/qt.cmake b/next/platform/qt/qt.cmake index 59aa00788f..b902388565 100644 --- a/next/platform/qt/qt.cmake +++ b/next/platform/qt/qt.cmake @@ -45,7 +45,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp ${MBGL_ROOT}/platform/qt/src/async_task.cpp ${MBGL_ROOT}/platform/qt/src/async_task_impl.hpp - ${MBGL_ROOT}/platform/qt/src/format_number.cpp + ${MBGL_ROOT}/platform/qt/src/number_format.cpp ${MBGL_ROOT}/platform/qt/src/gl_functions.cpp ${MBGL_ROOT}/platform/qt/src/headless_backend_qt.cpp ${MBGL_ROOT}/platform/qt/src/http_file_source.cpp diff --git a/platform/android/core-files.json b/platform/android/core-files.json index 4057b21000..e442883e47 100644 --- a/platform/android/core-files.json +++ b/platform/android/core-files.json @@ -34,6 +34,8 @@ "platform/android/src/gson/json_element.cpp", "platform/android/src/gson/json_object.cpp", "platform/android/src/gson/json_primitive.cpp", + "platform/android/src/i18n/collator.cpp", + "platform/android/src/i18n/number_format.cpp", "platform/android/src/image.cpp", "platform/android/src/java/util.cpp", "platform/android/src/java_types.cpp", @@ -80,9 +82,7 @@ "platform/android/src/style/sources/vector_source.cpp", "platform/android/src/style/transition_options.cpp", "platform/android/src/style/value.cpp", - "platform/android/src/i18n/collator.cpp", "platform/android/src/text/local_glyph_rasterizer.cpp", - "platform/android/src/text/format_number.cpp", "platform/android/src/gl_functions.cpp", "platform/android/src/thread.cpp", "platform/android/src/timer.cpp", @@ -143,6 +143,8 @@ "java_types.hpp": "platform/android/src/java_types.hpp", "jni.hpp": "platform/android/src/jni.hpp", "jni_native.hpp": "platform/android/src/jni_native.hpp", + "i18n/collator_jni.hpp": "platform/android/src/i18n/collator_jni.hpp", + "i18n/number_format_jni.hpp": "platform/android/src/i18n/number_format_jni.hpp", "logger.hpp": "platform/android/src/logger.hpp", "map/camera_position.hpp": "platform/android/src/map/camera_position.hpp", "map/image.hpp": "platform/android/src/map/image.hpp", @@ -185,7 +187,6 @@ "style/sources/vector_source.hpp": "platform/android/src/style/sources/vector_source.hpp", "style/transition_options.hpp": "platform/android/src/style/transition_options.hpp", "style/value.hpp": "platform/android/src/style/value.hpp", - "text/collator_jni.hpp": "platform/android/src/i18n/collator_jni.hpp", "text/local_glyph_rasterizer_jni.hpp": "platform/android/src/text/local_glyph_rasterizer_jni.hpp" } } diff --git a/platform/android/src/i18n/number_format.cpp b/platform/android/src/i18n/number_format.cpp new file mode 100644 index 0000000000..c8e0b70562 --- /dev/null +++ b/platform/android/src/i18n/number_format.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include + +#include "../attach_env.hpp" +#include "number_format_jni.hpp" + +namespace mbgl { +namespace android { + +void NumberFormat::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "format"); + return nf.Call(env, method, number); +} + +void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); + return nf.Call(env, method, value); +} + +void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { + static auto& javaClass = jni::Class::Singleton(env); + static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); + return nf.Call(env, method, value); +} + +} // namespace android + +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + auto env{ android::AttachEnv() }; + + jni::Global> locale; + LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); + if (!languageTag.language) { + locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); + } else if (!languageTag.region) { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), + jni::Make(*env, *languageTag.region))); + } + + jni::Global> formatter; + if (currency.empty()) { + formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); + android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); + android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); + } else { + formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); + } + + auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); + return jni::Make(*env, result); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/android/src/i18n/number_format_jni.hpp b/platform/android/src/i18n/number_format_jni.hpp new file mode 100644 index 0000000000..1720038925 --- /dev/null +++ b/platform/android/src/i18n/number_format_jni.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "collator_jni.hpp" + +/* + android::NumberFormat is the JNI wrapper + of java/text/NumberFormat. + */ + +namespace mbgl { +namespace android { + +class NumberFormat { +public: + static constexpr auto Name() { return "java/text/NumberFormat"; }; + + static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); + static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); + static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/jni_native.cpp b/platform/android/src/jni_native.cpp index 966dc6a007..9fe14f8f1f 100644 --- a/platform/android/src/jni_native.cpp +++ b/platform/android/src/jni_native.cpp @@ -51,9 +51,9 @@ #include "snapshotter/map_snapshot.hpp" #endif #include "i18n/collator_jni.hpp" +#include "i18n/number_format_jni.hpp" #include "logger.hpp" #include "text/local_glyph_rasterizer_jni.hpp" -#include "text/format_number_jni.hpp" namespace mbgl { namespace android { diff --git a/platform/android/src/text/format_number.cpp b/platform/android/src/text/format_number.cpp deleted file mode 100644 index 3a41175ecc..0000000000 --- a/platform/android/src/text/format_number.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include - -#include - -#include "../attach_env.hpp" -#include "format_number_jni.hpp" - -namespace mbgl { -namespace android { - -void NumberFormat::registerNative(jni::JNIEnv& env) { - jni::Class::Singleton(env); -} - -jni::Local> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getInstance"); - return javaClass.Call(env, method, locale); -} - -jni::Local> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object& locale) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetStaticMethod (jni::Object)>(env, "getCurrencyInstance"); - return javaClass.Call(env, method, locale); -} - -jni::Local NumberFormat::format(jni::JNIEnv& env, const jni::Object& nf, jni::jdouble number) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "format"); - return nf.Call(env, method, number); -} - -void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setMinimumFractionDigits"); - return nf.Call(env, method, value); -} - -void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object& nf, jni::jint value) { - static auto& javaClass = jni::Class::Singleton(env); - static auto method = javaClass.GetMethod(env, "setMaximumFractionDigits"); - return nf.Call(env, method, value); -} - -} // namespace android - -namespace platform { - -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits) { - - auto env{ android::AttachEnv() }; - - jni::Global> locale; - LanguageTag languageTag = !localeId.empty() ? LanguageTag::fromBCP47(localeId) : LanguageTag(); - if (!languageTag.language) { - locale = jni::NewGlobal(*env, android::Locale::getDefault(*env)); - } else if (!languageTag.region) { - locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language))); - } else { - locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make(*env, *languageTag.language), - jni::Make(*env, *languageTag.region))); - } - - jni::Global> formatter; - if (currency.empty()) { - formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); - android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast(minFractionDigits)); - android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast(maxFractionDigits)); - } else { - formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); - } - - auto result = android::NumberFormat::format(*env, formatter, static_cast(number)); - return jni::Make(*env, result); -} - -} // namespace platform -} // namespace mbgl diff --git a/platform/android/src/text/format_number_jni.hpp b/platform/android/src/text/format_number_jni.hpp deleted file mode 100644 index 1b63012c6e..0000000000 --- a/platform/android/src/text/format_number_jni.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "../i18n/collator_jni.hpp" - -/* - android::NumberFormat is the JNI wrapper - of java/text/NumberFormat. - */ - -namespace mbgl { -namespace android { - -class NumberFormat { -public: - static constexpr auto Name() { return "java/text/NumberFormat"; }; - - static jni::Local> getInstance(jni::JNIEnv&, const jni::Object&); - static jni::Local> getCurrencyInstance(jni::JNIEnv&, const jni::Object&); - static jni::Local format(jni::JNIEnv&, const jni::Object&, jni::jdouble); - static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); - static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object&, jni::jint); - - static void registerNative(jni::JNIEnv&); -}; - -} // namespace android -} // namespace mbgl diff --git a/platform/darwin/src/number_format.mm b/platform/darwin/src/number_format.mm new file mode 100644 index 0000000000..86f16eb6dd --- /dev/null +++ b/platform/darwin/src/number_format.mm @@ -0,0 +1,36 @@ +#import + +#include + +namespace mbgl { +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + static NSNumberFormatter *numberFormatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + numberFormatter = [[NSNumberFormatter alloc] init]; + }); + + numberFormatter.locale = !localeId.empty() ? [NSLocale localeWithLocaleIdentifier:@(localeId.c_str())] : nil; + numberFormatter.currencyCode = !currency.empty() ? @(currency.c_str()) : nil; + if (currency.empty()) { + numberFormatter.minimumFractionDigits = minFractionDigits; + numberFormatter.maximumFractionDigits = maxFractionDigits; + numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; + } else { + // Reset fraction digits to NSNumberFormatter's default values, so that the + // system will choose formatting based on number formatter locale. + numberFormatter.minimumFractionDigits = 0; + numberFormatter.maximumFractionDigits = 0; + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + } + NSString *formatted = [numberFormatter stringFromNumber:@(number)]; + std::string result = std::string([formatted UTF8String]); + return result; +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/darwin/src/string_nsstring.mm b/platform/darwin/src/string_nsstring.mm index 382a2acf33..d7c81236ef 100644 --- a/platform/darwin/src/string_nsstring.mm +++ b/platform/darwin/src/string_nsstring.mm @@ -27,32 +27,5 @@ std::string lowercase(const std::string &string) { return result; } -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits) { - - static NSNumberFormatter *numberFormatter; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - numberFormatter = [[NSNumberFormatter alloc] init]; - }); - - numberFormatter.locale = !localeId.empty() ? [NSLocale localeWithLocaleIdentifier:@(localeId.c_str())] : nil; - numberFormatter.currencyCode = !currency.empty() ? @(currency.c_str()) : nil; - if (currency.empty()) { - numberFormatter.minimumFractionDigits = minFractionDigits; - numberFormatter.maximumFractionDigits = maxFractionDigits; - numberFormatter.numberStyle = NSNumberFormatterDecimalStyle; - } else { - // Reset fraction digits to NSNumberFormatter's default values, so that the - // system will choose formatting based on number formatter locale. - numberFormatter.minimumFractionDigits = 0; - numberFormatter.maximumFractionDigits = 0; - numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; - } - NSString *formatted = [numberFormatter stringFromNumber:@(number)]; - std::string result = std::string([formatted UTF8String]); - return result; -} - -} -} +} // namespace platform +} // namespace mbgl diff --git a/platform/default/src/mbgl/i18n/format_number.cpp b/platform/default/src/mbgl/i18n/format_number.cpp new file mode 100644 index 0000000000..7b6f24221d --- /dev/null +++ b/platform/default/src/mbgl/i18n/format_number.cpp @@ -0,0 +1,39 @@ +#include + +#include + +namespace mbgl { +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString ustr; + std::string formatted; + + icu::Locale locale = icu::Locale(localeId.c_str()); + // Print the value as currency + if (!currency.empty()) { + icu::UnicodeString ucurrency = icu::UnicodeString::fromUTF8(currency); + ustr = icu::number::NumberFormatter::with() + .unit(icu::CurrencyUnit(ucurrency.getBuffer(), status)) + .locale(locale) + .formatDouble(number, status) + .toString(); + } else { + ustr = icu::number::NumberFormatter::with() +#if U_ICU_VERSION_MAJOR_NUM >= 62 + .precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)) +#else + .rounding(icu::number::Rounder::minMaxFraction(minFractionDigits, maxFractionDigits)) +#endif + .locale(locale) + .formatDouble(number, status) + .toString(); + } + return ustr.toUTF8String(formatted); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/default/src/mbgl/i18n/number_format.cpp b/platform/default/src/mbgl/i18n/number_format.cpp new file mode 100644 index 0000000000..7f2bc5a5ef --- /dev/null +++ b/platform/default/src/mbgl/i18n/number_format.cpp @@ -0,0 +1,41 @@ +#include + +#include + +namespace mbgl { +namespace platform { + +std::string formatNumber(double number, + const std::string& localeId, + const std::string& currency, + uint8_t minFractionDigits, + uint8_t maxFractionDigits) { + UErrorCode status = U_ZERO_ERROR; + icu::UnicodeString ustr; + std::string formatted; + + icu::Locale locale = icu::Locale(localeId.c_str()); + // Print the value as currency + if (!currency.empty()) { + icu::UnicodeString ucurrency = icu::UnicodeString::fromUTF8(currency); + ustr = icu::number::NumberFormatter::with() + .unit(icu::CurrencyUnit(ucurrency.getBuffer(), status)) + .locale(locale) + .formatDouble(number, status) + .toString(); + } else { + ustr = icu::number::NumberFormatter::with() +#if U_ICU_VERSION_MAJOR_NUM >= 62 + .precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)) +#else + .rounding(icu::number::Rounder::minMaxFraction(minFractionDigits, maxFractionDigits)) +#endif + .locale(locale) + .formatDouble(number, status) + .toString(); + } + return ustr.toUTF8String(formatted); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/default/src/mbgl/util/format_number.cpp b/platform/default/src/mbgl/util/format_number.cpp deleted file mode 100644 index d1b51e11a1..0000000000 --- a/platform/default/src/mbgl/util/format_number.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include - -namespace mbgl { -namespace platform { - -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits) { - - UErrorCode status = U_ZERO_ERROR; - icu::UnicodeString ustr; - std::string formatted; - - icu::Locale locale = icu::Locale(localeId.c_str()); - // Print the value as currency - if (!currency.empty()) { - icu::UnicodeString ucurrency = icu::UnicodeString::fromUTF8(currency); - ustr = icu::number::NumberFormatter::with() - .unit(icu::CurrencyUnit(ucurrency.getBuffer(), status)) - .locale(locale) - .formatDouble(number, status) - .toString(); - } else { - ustr = icu::number::NumberFormatter::with() -#if U_ICU_VERSION_MAJOR_NUM >= 62 - .precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)) -#else - .rounding(icu::number::Rounder::minMaxFraction(minFractionDigits, maxFractionDigits)) -#endif - .locale(locale) - .formatDouble(number, status) - .toString(); - } - return ustr.toUTF8String(formatted); -} - -} // namespace platform -} // namespace mbgl diff --git a/platform/ios/core-files.json b/platform/ios/core-files.json index c4930b1667..7c916b027b 100644 --- a/platform/ios/core-files.json +++ b/platform/ios/core-files.json @@ -7,6 +7,7 @@ "platform/darwin/src/image.mm", "platform/darwin/src/local_glyph_rasterizer.mm", "platform/darwin/src/logging_nslog.mm", + "platform/darwin/src/number_format.mm", "platform/darwin/src/nsthread.mm", "platform/darwin/src/reachability.m", "platform/darwin/src/string_nsstring.mm", diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 01c46c9fcb..26de2430ce 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -45,17 +45,17 @@ macro(mbgl_platform_core) PRIVATE platform/linux/src/gl_functions.cpp # Misc + PRIVATE platform/default/src/mbgl/i18n/collator.cpp + PRIVATE platform/default/src/mbgl/i18n/number_format.cpp + PRIVATE platform/default/src/mbgl/text/bidi.cpp + PRIVATE platform/default/src/mbgl/text/local_glyph_rasterizer.cpp + PRIVATE platform/default/src/mbgl/layermanager/layer_manager.cpp PRIVATE platform/default/src/mbgl/util/compression.cpp PRIVATE platform/default/src/mbgl/util/logging_stderr.cpp PRIVATE platform/default/src/mbgl/util/string_stdlib.cpp PRIVATE platform/default/src/mbgl/util/thread.cpp - PRIVATE platform/default/src/mbgl/text/bidi.cpp - PRIVATE platform/default/src/mbgl/i18n/collator.cpp - PRIVATE platform/default/src/mbgl/layermanager/layer_manager.cpp - PRIVATE platform/default/src/mbgl/text/local_glyph_rasterizer.cpp PRIVATE platform/default/src/mbgl/util/thread_local.cpp PRIVATE platform/default/src/mbgl/util/utf.cpp - PRIVATE platform/default/src/mbgl/util/format_number.cpp # Image handling PRIVATE platform/default/src/mbgl/util/image.cpp @@ -86,7 +86,7 @@ macro(mbgl_platform_core) target_add_mason_package(mbgl-core PRIVATE icu) # Ignore warning caused by ICU header unistr.h in some CI environments - set_source_files_properties(platform/default/src/mbgl/util/format_number.cpp PROPERTIES COMPILE_FLAGS -Wno-error=shadow) + set_source_files_properties(platform/default/src/mbgl/i18n/number_format.cpp PROPERTIES COMPILE_FLAGS -Wno-error=shadow) # Link all ICU libraries (by default only libicuuc is linked) find_library(LIBICUI18N NAMES icui18n HINTS ${MASON_PACKAGE_icu_INCLUDE_DIRS}/../lib) diff --git a/platform/macos/core-files.json b/platform/macos/core-files.json index 21b0e698f0..b0536c4863 100644 --- a/platform/macos/core-files.json +++ b/platform/macos/core-files.json @@ -7,6 +7,7 @@ "platform/darwin/src/local_glyph_rasterizer.mm", "platform/darwin/src/logging_nslog.mm", "platform/darwin/src/nsthread.mm", + "platform/darwin/src/number_format.mm", "platform/darwin/src/reachability.m", "platform/darwin/src/string_nsstring.mm", "platform/default/src/mbgl/gfx/headless_backend.cpp", diff --git a/platform/qt/src/format_number.cpp b/platform/qt/src/format_number.cpp deleted file mode 100644 index b6fe3558e6..0000000000 --- a/platform/qt/src/format_number.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include - -#include -#include - -namespace mbgl { -namespace platform { - -std::string formatNumber(double number, const std::string& localeId, const std::string& currency, - uint8_t minFractionDigits, uint8_t maxFractionDigits) { - - QString formatted; - // Qt Locale::toString() API takes only one precision argument - (void)minFractionDigits; - QLocale locale = QLocale(QString::fromStdString(localeId)); - - if (!currency.empty()) { - formatted = locale.toCurrencyString(number); - } else { - formatted = locale.toString(number, 'f', maxFractionDigits); - } - return formatted.toStdString(); -} - -} // namespace platform -} // namespace mbgl diff --git a/platform/qt/src/number_format.cpp b/platform/qt/src/number_format.cpp new file mode 100644 index 0000000000..b6fe3558e6 --- /dev/null +++ b/platform/qt/src/number_format.cpp @@ -0,0 +1,26 @@ +#include + +#include +#include + +namespace mbgl { +namespace platform { + +std::string formatNumber(double number, const std::string& localeId, const std::string& currency, + uint8_t minFractionDigits, uint8_t maxFractionDigits) { + + QString formatted; + // Qt Locale::toString() API takes only one precision argument + (void)minFractionDigits; + QLocale locale = QLocale(QString::fromStdString(localeId)); + + if (!currency.empty()) { + formatted = locale.toCurrencyString(number); + } else { + formatted = locale.toString(number, 'f', maxFractionDigits); + } + return formatted.toStdString(); +} + +} // namespace platform +} // namespace mbgl diff --git a/src/core-files.json b/src/core-files.json index 2f609e92ec..a460ab86df 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -333,6 +333,8 @@ "mbgl/gfx/renderer_backend.hpp": "include/mbgl/gfx/renderer_backend.hpp", "mbgl/gl/renderable_resource.hpp": "include/mbgl/gl/renderable_resource.hpp", "mbgl/gl/renderer_backend.hpp": "include/mbgl/gl/renderer_backend.hpp", + "mbgl/i18n/collator.hpp": "include/mbgl/i18n/collator.hpp", + "mbgl/i18n/number_format.hpp": "include/mbgl/i18n/number_format.hpp", "mbgl/layermanager/background_layer_factory.hpp": "include/mbgl/layermanager/background_layer_factory.hpp", "mbgl/layermanager/circle_layer_factory.hpp": "include/mbgl/layermanager/circle_layer_factory.hpp", "mbgl/layermanager/custom_layer_factory.hpp": "include/mbgl/layermanager/custom_layer_factory.hpp", diff --git a/src/mbgl/style/expression/number_format.cpp b/src/mbgl/style/expression/number_format.cpp index e31a9ce398..c2de032ff4 100644 --- a/src/mbgl/style/expression/number_format.cpp +++ b/src/mbgl/style/expression/number_format.cpp @@ -1,6 +1,6 @@ -#include +#include #include -#include +#include namespace mbgl { namespace style { -- cgit v1.2.1 From 18dcf38a7a6e42f19604a9626b15fff2570093b6 Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Wed, 25 Sep 2019 17:37:48 +0300 Subject: [android] Remove usage of ResourceOptions::withPlatformContext --- next/platform/android/android.cmake | 2 + .../src/main/java/com/mapbox/mapboxsdk/Mapbox.java | 10 +++++ .../com/mapbox/mapboxsdk/storage/FileSource.java | 9 ++--- platform/android/core-files.json | 2 + platform/android/src/file_source.cpp | 47 +++++++++++----------- platform/android/src/file_source.hpp | 2 +- platform/android/src/jni_native.cpp | 6 ++- platform/android/src/mapbox.cpp | 17 ++++++++ platform/android/src/mapbox.hpp | 18 +++++++++ 9 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 platform/android/src/mapbox.cpp create mode 100644 platform/android/src/mapbox.hpp diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index 507c1baef0..13818e39a7 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -101,6 +101,8 @@ target_sources( ${MBGL_ROOT}/platform/android/src/logger.cpp ${MBGL_ROOT}/platform/android/src/logger.hpp ${MBGL_ROOT}/platform/android/src/logging_android.cpp + ${MBGL_ROOT}/platform/android/src/mapbox.cpp + ${MBGL_ROOT}/platform/android/src/mapbox.hpp ${MBGL_ROOT}/platform/android/src/map/camera_position.cpp ${MBGL_ROOT}/platform/android/src/map/camera_position.hpp ${MBGL_ROOT}/platform/android/src/map/image.cpp diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 01c82ddad4..9c2ae8492c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk; import android.annotation.SuppressLint; import android.content.Context; +import android.content.res.AssetManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; @@ -222,4 +223,13 @@ public final class Mapbox { public static boolean hasInstance() { return INSTANCE != null; } + + /** + * Internal use. Returns AssetManager. + * + * @return the asset manager + */ + private static AssetManager getAssetManager() { + return getApplicationContext().getResources().getAssets(); + } } \ No newline at end of file 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 763c97cca7..07e5b7e16d 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 @@ -4,7 +4,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.AssetManager; import android.os.AsyncTask; import android.os.Environment; import android.support.annotation.Keep; @@ -90,7 +89,7 @@ public class FileSource { @UiThread public static synchronized FileSource getInstance(@NonNull Context context) { if (INSTANCE == null) { - INSTANCE = new FileSource(getResourcesCachePath(context), context.getResources().getAssets()); + INSTANCE = new FileSource(getResourcesCachePath(context)); } return INSTANCE; @@ -366,8 +365,8 @@ public class FileSource { @Keep private long nativePtr; - private FileSource(String cachePath, AssetManager assetManager) { - initialize(Mapbox.getAccessToken(), cachePath, assetManager); + private FileSource(String cachePath) { + initialize(Mapbox.getAccessToken(), cachePath); } @Keep @@ -404,7 +403,7 @@ public class FileSource { private native void setResourceCachePath(String path, ResourcesCachePathChangeCallback callback); @Keep - private native void initialize(String accessToken, String cachePath, AssetManager assetManager); + private native void initialize(String accessToken, String cachePath); @Override @Keep diff --git a/platform/android/core-files.json b/platform/android/core-files.json index e442883e47..d536247154 100644 --- a/platform/android/core-files.json +++ b/platform/android/core-files.json @@ -43,6 +43,7 @@ "platform/android/src/jni_native.cpp", "platform/android/src/logger.cpp", "platform/android/src/logging_android.cpp", + "platform/android/src/mapbox.cpp", "platform/android/src/map/camera_position.cpp", "platform/android/src/map/image.cpp", "platform/android/src/map_renderer.cpp", @@ -146,6 +147,7 @@ "i18n/collator_jni.hpp": "platform/android/src/i18n/collator_jni.hpp", "i18n/number_format_jni.hpp": "platform/android/src/i18n/number_format_jni.hpp", "logger.hpp": "platform/android/src/logger.hpp", + "mapbox.hpp": "platform/android/src/mapbox.hpp", "map/camera_position.hpp": "platform/android/src/map/camera_position.hpp", "map/image.hpp": "platform/android/src/map/image.hpp", "map_renderer.hpp": "platform/android/src/map_renderer.hpp", diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 5f61aadba0..234d8d9758 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -1,5 +1,7 @@ #include "file_source.hpp" + #include "attach_env.hpp" +#include "mapbox.hpp" #include #include @@ -14,8 +16,10 @@ namespace mbgl { std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { - auto* assetFileSource = reinterpret_cast(options.platformContext()); - auto fileSource = std::make_shared(options.cachePath(), std::unique_ptr(assetFileSource)); + auto env{android::AttachEnv()}; + auto assetManager = android::Mapbox::getAssetManager(*env); + auto fileSource = std::make_shared(options.cachePath(), + std::make_unique(*env, assetManager)); fileSource->setAccessToken(options.accessToken()); return fileSource; } @@ -24,17 +28,12 @@ namespace android { // FileSource // -FileSource::FileSource(jni::JNIEnv& _env, - const jni::String& accessToken, - const jni::String& _cachePath, - const jni::Object& assetManager) { +FileSource::FileSource(jni::JNIEnv& _env, const jni::String& accessToken, const jni::String& _cachePath) { std::string path = jni::Make(_env, _cachePath); mapbox::sqlite::setTempPath(path); - resourceOptions - .withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") - .withCachePath(path + DATABASE_FILE) - .withPlatformContext(reinterpret_cast(new AssetManagerFileSource(_env, assetManager))); + resourceOptions.withAccessToken(accessToken ? jni::Make(_env, accessToken) : "") + .withCachePath(path + DATABASE_FILE); // Create a core default file source fileSource = std::static_pointer_cast(mbgl::FileSource::getSharedFileSource(resourceOptions)); @@ -171,20 +170,20 @@ void FileSource::registerNative(jni::JNIEnv& env) { #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) // Register the peer - jni::RegisterNativePeer( - env, javaClass, "nativePtr", - jni::MakePeer&>, - "initialize", - "finalize", - METHOD(&FileSource::getAccessToken, "getAccessToken"), - METHOD(&FileSource::setAccessToken, "setAccessToken"), - METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), - METHOD(&FileSource::setResourceTransform, "setResourceTransform"), - METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), - METHOD(&FileSource::resume, "activate"), - METHOD(&FileSource::pause, "deactivate"), - METHOD(&FileSource::isResumed, "isActivated") - ); + jni::RegisterNativePeer(env, + javaClass, + "nativePtr", + jni::MakePeer, + "initialize", + "finalize", + METHOD(&FileSource::getAccessToken, "getAccessToken"), + METHOD(&FileSource::setAccessToken, "setAccessToken"), + METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"), + METHOD(&FileSource::setResourceTransform, "setResourceTransform"), + METHOD(&FileSource::setResourceCachePath, "setResourceCachePath"), + METHOD(&FileSource::resume, "activate"), + METHOD(&FileSource::pause, "deactivate"), + METHOD(&FileSource::isResumed, "isActivated")); } diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp index f3ad33eb31..6a9190fa06 100644 --- a/platform/android/src/file_source.hpp +++ b/platform/android/src/file_source.hpp @@ -41,7 +41,7 @@ public: const jni::String&); }; - FileSource(jni::JNIEnv&, const jni::String&, const jni::String&, const jni::Object&); + FileSource(jni::JNIEnv&, const jni::String&, const jni::String&); ~FileSource(); diff --git a/platform/android/src/jni_native.cpp b/platform/android/src/jni_native.cpp index 9fe14f8f1f..bcbdfcf484 100644 --- a/platform/android/src/jni_native.cpp +++ b/platform/android/src/jni_native.cpp @@ -6,8 +6,8 @@ #include "bitmap.hpp" #include "bitmap_factory.hpp" #include "connectivity_listener.hpp" -#include "conversion/conversion.hpp" #include "conversion/collection.hpp" +#include "conversion/conversion.hpp" #include "file_source.hpp" #include "geojson/feature.hpp" #include "geojson/feature_collection.hpp" @@ -32,6 +32,7 @@ #include "java_types.hpp" #include "map_renderer.hpp" #include "map_renderer_runnable.hpp" +#include "mapbox.hpp" #include "native_map_view.hpp" #ifndef MBGL_MODULE_OFFLINE_DISABLE #include "offline/offline_manager.hpp" @@ -158,6 +159,9 @@ void registerNatives(JavaVM *vm) { // Logger Logger::registerNative(env); + + // AssetManager + Mapbox::registerNative(env); } } // namespace android diff --git a/platform/android/src/mapbox.cpp b/platform/android/src/mapbox.cpp new file mode 100644 index 0000000000..c835518b42 --- /dev/null +++ b/platform/android/src/mapbox.cpp @@ -0,0 +1,17 @@ +#include "mapbox.hpp" + +namespace mbgl { +namespace android { + +jni::Local> Mapbox::getAssetManager(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + auto method = javaClass.GetStaticMethod()>(env, "getAssetManager"); + return javaClass.Call(env, method); +} + +void Mapbox::registerNative(jni::JNIEnv& env) { + jni::Class::Singleton(env); +} + +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/mapbox.hpp b/platform/android/src/mapbox.hpp new file mode 100644 index 0000000000..2d9a657fa1 --- /dev/null +++ b/platform/android/src/mapbox.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "asset_manager.hpp" + +#include + +namespace mbgl { +namespace android { + +class Mapbox { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/Mapbox"; }; + static jni::Local> getAssetManager(jni::JNIEnv&); + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl -- cgit v1.2.1 From 73a9d33b29fe4be9addf50c07a50de6131a6a002 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 19 Sep 2019 18:46:10 +0300 Subject: [build] Bump mapbox-base --- vendor/mapbox-base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-base b/vendor/mapbox-base index 8999704551..a951030b70 160000 --- a/vendor/mapbox-base +++ b/vendor/mapbox-base @@ -1 +1 @@ -Subproject commit 89997045511baf975dce1a3153d32b1fdd8bc69d +Subproject commit a951030b7076c74de3faed932e4f7b3700aa0947 -- cgit v1.2.1 From 2b834001cca8c2b0552c106dd404da1b238f043b Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 24 Sep 2019 17:44:39 +0300 Subject: [core] type aliases and conversion traits for mapbox::base::Value --- include/mbgl/style/conversion_impl.hpp | 54 +++++++++++++++++++++++++++++++++- include/mbgl/util/feature.hpp | 10 +++---- next/CMakeLists.txt | 1 + next/platform/android/android.cmake | 1 + scripts/generate-file-lists.js | 3 +- src/mbgl/util/color.cpp | 8 ++--- vendor/mapbox-base-files.json | 1 + 7 files changed, 67 insertions(+), 11 deletions(-) diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index f049ba4ffb..7ac4ec649b 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -1,11 +1,17 @@ #pragma once +#include #include -#include +#include #include #include +#include +#include + +#include #include +#include namespace mbgl { namespace style { @@ -288,6 +294,52 @@ optional convert(const Convertible& value, Error& error, Args&&...args) { return Converter()(value, error, std::forward(args)...); } +template +struct ValueFactory; + +template +struct ValueArrayFactory { + static Value make(const T& arg) { return mapbox::base::ValueArray(arg.begin(), arg.end()); } +}; + +template <> +struct ValueFactory> : public ValueArrayFactory> {}; + +template <> +struct ValueFactory> : public ValueArrayFactory> {}; + +template <> +struct ValueFactory { + static Value make(const ColorRampPropertyValue& value) { return value.getExpression().serialize(); } +}; + +template <> +struct ValueFactory { + static Value make(const Color& color) { return color.toObject(); } +}; + +template +struct ValueFactory::value>::type> { + static Value make(const T& arg) { return {arg}; } +}; + +template +struct ValueFactory::value>::type> { + static Value make(T arg) { return {int64_t(arg)}; } +}; + +template +Value makeValue(T&& arg) { + return ValueFactory>::make(std::forward(arg)); +} + +template +Value makeValue(const PropertyValue& value) { + return value.match([](const Undefined&) -> Value { return {}; }, + [](const T& t) -> Value { return makeValue(t); }, + [](const PropertyExpression& fn) { return fn.getExpression().serialize(); }); +} + } // namespace conversion } // namespace style } // namespace mbgl diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp index 390cc65720..6080976945 100644 --- a/include/mbgl/util/feature.hpp +++ b/include/mbgl/util/feature.hpp @@ -3,16 +3,16 @@ #include #include -#include +#include namespace mbgl { -using Value = mapbox::feature::value; -using NullValue = mapbox::feature::null_value_t; -using PropertyMap = mapbox::feature::property_map; +using Value = mapbox::base::Value; +using NullValue = mapbox::base::NullValue; +using PropertyMap = mapbox::base::ValueObject; using FeatureIdentifier = mapbox::feature::identifier; using Feature = mapbox::feature::feature; -using FeatureState = PropertyMap; +using FeatureState = mapbox::base::ValueObject; using FeatureStates = std::unordered_map; // using LayerFeatureStates = std::unordered_map; // diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index bc15f04420..dbf6c11918 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -912,6 +912,7 @@ target_link_libraries( Mapbox::Base::geometry.hpp Mapbox::Base::optional Mapbox::Base::typewrapper + Mapbox::Base::value Mapbox::Base::variant Mapbox::Base::weak mbgl-vendor-expected diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index 13818e39a7..1bde72d11d 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -268,6 +268,7 @@ target_link_libraries( GLESv2 Mapbox::Base::optional Mapbox::Base::typewrapper + Mapbox::Base::value Mapbox::Base::weak log ) diff --git a/scripts/generate-file-lists.js b/scripts/generate-file-lists.js index d1f5e77585..546ce38235 100755 --- a/scripts/generate-file-lists.js +++ b/scripts/generate-file-lists.js @@ -145,7 +145,8 @@ generateFileList('vendor/mapbox-base-files.json', 'vendor/mapbox-base/mapbox/geojson.hpp', 'vendor/mapbox-base/mapbox/jni.hpp', 'vendor/mapbox-base/mapbox/weak', - 'vendor/mapbox-base/mapbox/typewrapper' ], + 'vendor/mapbox-base/mapbox/typewrapper', + 'vendor/mapbox-base/mapbox/value'], vendorRegex, [ "include/*.hpp", "include/**/*.hpp", "include/**/*.h", "optional.hpp", ":!:include/jni/string_conversion.hpp" ]); generateFileList('vendor/polylabel-files.json', [ 'vendor/polylabel' ], vendorRegex, [ "include/**/*.hpp" ]); generateFileList('vendor/protozero-files.json', [ 'vendor/protozero' ], vendorRegex, [ "include/**/*.hpp" ]); diff --git a/src/mbgl/util/color.cpp b/src/mbgl/util/color.cpp index 4c2814cf14..8a880e8760 100644 --- a/src/mbgl/util/color.cpp +++ b/src/mbgl/util/color.cpp @@ -45,10 +45,10 @@ std::array Color::toArray() const { } mbgl::Value Color::toObject() const { - return std::unordered_map{{"r", double(r)}, - {"g", double(g)}, - {"b", double(b)}, - {"a", double(a)}}; + return mapbox::base::ValueObject{{"r", double(r)}, + {"g", double(g)}, + {"b", double(b)}, + {"a", double(a)}}; } } // namespace mbgl diff --git a/vendor/mapbox-base-files.json b/vendor/mapbox-base-files.json index 7c638d2b80..55091e438d 100644 --- a/vendor/mapbox-base-files.json +++ b/vendor/mapbox-base-files.json @@ -94,6 +94,7 @@ "mapbox/pixelmatch.hpp": "vendor/mapbox-base/mapbox/pixelmatch-cpp/include/mapbox/pixelmatch.hpp", "supercluster.hpp": "vendor/mapbox-base/mapbox/supercluster.hpp/include/supercluster.hpp", "mapbox/type_wrapper.hpp": "vendor/mapbox-base/mapbox/typewrapper/include/mapbox/type_wrapper.hpp", + "mapbox/value.hpp": "vendor/mapbox-base/mapbox/value/include/mapbox/value.hpp", "mapbox/optional.hpp": "vendor/mapbox-base/mapbox/variant/include/mapbox/optional.hpp", "mapbox/recursive_wrapper.hpp": "vendor/mapbox-base/mapbox/variant/include/mapbox/recursive_wrapper.hpp", "mapbox/variant.hpp": "vendor/mapbox-base/mapbox/variant/include/mapbox/variant.hpp", -- cgit v1.2.1 From c2dc873cf9c026e964d1d73a2c8301d21509da6e Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 24 Sep 2019 23:06:05 +0300 Subject: [core] Introduce Layer::getPaintProperty() generic getter --- include/mbgl/style/conversion_impl.hpp | 35 +++- include/mbgl/style/layer.hpp | 18 +- include/mbgl/style/layers/background_layer.hpp | 2 + include/mbgl/style/layers/circle_layer.hpp | 2 + include/mbgl/style/layers/custom_layer.hpp | 2 +- include/mbgl/style/layers/fill_extrusion_layer.hpp | 2 + include/mbgl/style/layers/fill_layer.hpp | 2 + include/mbgl/style/layers/heatmap_layer.hpp | 2 + include/mbgl/style/layers/hillshade_layer.hpp | 2 + include/mbgl/style/layers/layer.hpp.ejs | 2 + include/mbgl/style/layers/line_layer.hpp | 2 + include/mbgl/style/layers/raster_layer.hpp | 2 + include/mbgl/style/layers/symbol_layer.hpp | 2 + src/mbgl/style/layers/background_layer.cpp | 66 ++++--- src/mbgl/style/layers/circle_layer.cpp | 162 +++++++++++------ src/mbgl/style/layers/custom_layer.cpp | 4 + src/mbgl/style/layers/fill_extrusion_layer.cpp | 126 ++++++++----- src/mbgl/style/layers/fill_layer.cpp | 114 ++++++++---- src/mbgl/style/layers/heatmap_layer.cpp | 90 +++++++--- src/mbgl/style/layers/hillshade_layer.cpp | 102 +++++++---- src/mbgl/style/layers/layer.cpp.ejs | 44 +++-- src/mbgl/style/layers/line_layer.cpp | 162 +++++++++++------ src/mbgl/style/layers/raster_layer.cpp | 126 ++++++++----- src/mbgl/style/layers/symbol_layer.cpp | 198 ++++++++++++++------- src/mbgl/util/color.cpp | 5 +- 25 files changed, 887 insertions(+), 387 deletions(-) diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 7ac4ec649b..866eff9eb5 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -2,7 +2,9 @@ #include #include +#include #include +#include #include #include #include @@ -10,6 +12,7 @@ #include #include +#include #include #include @@ -313,6 +316,18 @@ struct ValueFactory { static Value make(const ColorRampPropertyValue& value) { return value.getExpression().serialize(); } }; +template <> +struct ValueFactory { + static Value make(const TransitionOptions& value) { + return mapbox::base::ValueArray{ + {std::chrono::duration_cast(value.duration.value_or(mbgl::Duration::zero())) + .count(), + std::chrono::duration_cast(value.delay.value_or(mbgl::Duration::zero())) + .count(), + value.enablePlacementTransitions}}; + } +}; + template <> struct ValueFactory { static Value make(const Color& color) { return color.toObject(); } @@ -334,10 +349,22 @@ Value makeValue(T&& arg) { } template -Value makeValue(const PropertyValue& value) { - return value.match([](const Undefined&) -> Value { return {}; }, - [](const T& t) -> Value { return makeValue(t); }, - [](const PropertyExpression& fn) { return fn.getExpression().serialize(); }); +LayerProperty makeLayerProperty(const PropertyValue& value) { + return value.match([](const Undefined&) -> LayerProperty { return {}; }, + [](const T& t) -> LayerProperty { + return {makeValue(t), LayerProperty::Kind::Constant}; + }, + [](const PropertyExpression& fn) -> LayerProperty { + return {fn.getExpression().serialize(), LayerProperty::Kind::Expression}; + }); +} + +inline LayerProperty makeLayerProperty(const TransitionOptions& value) { + return {makeValue(value), LayerProperty::Kind::Transition}; +} + +inline LayerProperty makeLayerProperty(const ColorRampPropertyValue& value) { + return {makeValue(value), LayerProperty::Kind::Expression}; } } // namespace conversion diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index 35577411eb..646bad898c 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -1,9 +1,10 @@ #pragma once +#include +#include +#include #include #include -#include -#include #include #include @@ -65,6 +66,14 @@ struct LayerTypeInfo { const enum class TileKind : uint8_t { Geometry, Raster, RasterDEM, NotRequired } tileKind; }; +struct LayerProperty { + enum class Kind : uint8_t { Undefined, Constant, Expression, Transition }; + LayerProperty(Value value_, Kind kind_) : value(std::move(value_)), kind(kind_) {} + LayerProperty() = default; + const Value value; + const Kind kind = Kind::Undefined; +}; + /** * The runtime representation of a [layer](https://www.mapbox.com/mapbox-gl-style-spec/#layers) from the Mapbox Style * Specification. @@ -110,9 +119,12 @@ public: // Dynamic properties virtual optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) = 0; - virtual optional setPaintProperty(const std::string& name, const conversion::Convertible& value) = 0; + virtual optional setPaintProperty(const std::string& name, + const conversion::Convertible& value) = 0; optional setVisibility(const conversion::Convertible& value); + virtual LayerProperty getPaintProperty(const std::string&) const = 0; + // Private implementation // TODO : We should not have public mutable data members. class Impl; diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp index 4a73ae4a0b..8caade26b0 100644 --- a/include/mbgl/style/layers/background_layer.hpp +++ b/include/mbgl/style/layers/background_layer.hpp @@ -24,6 +24,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static PropertyValue getDefaultBackgroundColor(); diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp index f171805806..be4fe5cee4 100644 --- a/include/mbgl/style/layers/circle_layer.hpp +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -24,6 +24,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static PropertyValue getDefaultCircleBlur(); diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp index 4ae59dfae3..9ae68c4fff 100644 --- a/include/mbgl/style/layers/custom_layer.hpp +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -71,7 +71,7 @@ public: // Dynamic properties optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - + LayerProperty getPaintProperty(const std::string&) const final; // Private implementation class Impl; diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp index 2e89032ae7..63ccf369d4 100644 --- a/include/mbgl/style/layers/fill_extrusion_layer.hpp +++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp @@ -24,6 +24,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static PropertyValue getDefaultFillExtrusionBase(); diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp index 0c4369de4c..acf60cec0d 100644 --- a/include/mbgl/style/layers/fill_layer.hpp +++ b/include/mbgl/style/layers/fill_layer.hpp @@ -24,6 +24,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static PropertyValue getDefaultFillAntialias(); diff --git a/include/mbgl/style/layers/heatmap_layer.hpp b/include/mbgl/style/layers/heatmap_layer.hpp index 2023d8c21e..7eb7bb8edd 100644 --- a/include/mbgl/style/layers/heatmap_layer.hpp +++ b/include/mbgl/style/layers/heatmap_layer.hpp @@ -25,6 +25,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static ColorRampPropertyValue getDefaultHeatmapColor(); diff --git a/include/mbgl/style/layers/hillshade_layer.hpp b/include/mbgl/style/layers/hillshade_layer.hpp index f6b04a0062..7c8f6fa573 100644 --- a/include/mbgl/style/layers/hillshade_layer.hpp +++ b/include/mbgl/style/layers/hillshade_layer.hpp @@ -24,6 +24,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static PropertyValue getDefaultHillshadeAccentColor(); diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index 638db5fe4b..f678adeda7 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -40,6 +40,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + <% if (layoutProperties.length) { -%> // Layout properties diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp index 8f1d51295c..a1c69e9475 100644 --- a/include/mbgl/style/layers/line_layer.hpp +++ b/include/mbgl/style/layers/line_layer.hpp @@ -27,6 +27,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Layout properties static PropertyValue getDefaultLineCap(); diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp index ba2ea45428..e516e1a0fc 100644 --- a/include/mbgl/style/layers/raster_layer.hpp +++ b/include/mbgl/style/layers/raster_layer.hpp @@ -24,6 +24,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Paint properties static PropertyValue getDefaultRasterBrightnessMax(); diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index b60e991f49..578d7d1701 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -26,6 +26,8 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + LayerProperty getPaintProperty(const std::string& name) const final; + // Layout properties static PropertyValue getDefaultIconAllowOverlap(); diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 7a186a3354..4c37022e70 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -148,27 +148,30 @@ TransitionOptions BackgroundLayer::getBackgroundPatternTransition() const { using namespace conversion; +namespace { + +enum class Property { + BackgroundColor, + BackgroundOpacity, + BackgroundPattern, + BackgroundColorTransition, + BackgroundOpacityTransition, + BackgroundPatternTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"background-color", mbgl::underlying_type(Property::BackgroundColor)}, + {"background-opacity", mbgl::underlying_type(Property::BackgroundOpacity)}, + {"background-pattern", mbgl::underlying_type(Property::BackgroundPattern)}, + {"background-color-transition", mbgl::underlying_type(Property::BackgroundColorTransition)}, + {"background-opacity-transition", mbgl::underlying_type(Property::BackgroundOpacityTransition)}, + {"background-pattern-transition", mbgl::underlying_type(Property::BackgroundPatternTransition)}}); + +} // namespace + optional BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - BackgroundColor, - BackgroundOpacity, - BackgroundPattern, - BackgroundColorTransition, - BackgroundOpacityTransition, - BackgroundPatternTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "background-color", mbgl::underlying_type(Property::BackgroundColor) }, - { "background-opacity", mbgl::underlying_type(Property::BackgroundOpacity) }, - { "background-pattern", mbgl::underlying_type(Property::BackgroundPattern) }, - { "background-color-transition", mbgl::underlying_type(Property::BackgroundColorTransition) }, - { "background-opacity-transition", mbgl::underlying_type(Property::BackgroundOpacityTransition) }, - { "background-pattern-transition", mbgl::underlying_type(Property::BackgroundPatternTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -237,6 +240,29 @@ optional BackgroundLayer::setPaintProperty(const std::string& name, const return Error { "layer doesn't support this property" }; } +LayerProperty BackgroundLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::BackgroundColor: + return conversion::makeLayerProperty(getBackgroundColor()); + case Property::BackgroundOpacity: + return conversion::makeLayerProperty(getBackgroundOpacity()); + case Property::BackgroundPattern: + return conversion::makeLayerProperty(getBackgroundPattern()); + case Property::BackgroundColorTransition: + return conversion::makeLayerProperty(getBackgroundColorTransition()); + case Property::BackgroundOpacityTransition: + return conversion::makeLayerProperty(getBackgroundOpacityTransition()); + case Property::BackgroundPatternTransition: + return conversion::makeLayerProperty(getBackgroundPatternTransition()); + } + return {}; +} + optional BackgroundLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 2f68bcccf3..3fec7fd677 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -364,59 +364,62 @@ TransitionOptions CircleLayer::getCircleTranslateAnchorTransition() const { using namespace conversion; +namespace { + +enum class Property { + CircleBlur, + CircleColor, + CircleOpacity, + CirclePitchAlignment, + CirclePitchScale, + CircleRadius, + CircleStrokeColor, + CircleStrokeOpacity, + CircleStrokeWidth, + CircleTranslate, + CircleTranslateAnchor, + CircleBlurTransition, + CircleColorTransition, + CircleOpacityTransition, + CirclePitchAlignmentTransition, + CirclePitchScaleTransition, + CircleRadiusTransition, + CircleStrokeColorTransition, + CircleStrokeOpacityTransition, + CircleStrokeWidthTransition, + CircleTranslateTransition, + CircleTranslateAnchorTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"circle-blur", mbgl::underlying_type(Property::CircleBlur)}, + {"circle-color", mbgl::underlying_type(Property::CircleColor)}, + {"circle-opacity", mbgl::underlying_type(Property::CircleOpacity)}, + {"circle-pitch-alignment", mbgl::underlying_type(Property::CirclePitchAlignment)}, + {"circle-pitch-scale", mbgl::underlying_type(Property::CirclePitchScale)}, + {"circle-radius", mbgl::underlying_type(Property::CircleRadius)}, + {"circle-stroke-color", mbgl::underlying_type(Property::CircleStrokeColor)}, + {"circle-stroke-opacity", mbgl::underlying_type(Property::CircleStrokeOpacity)}, + {"circle-stroke-width", mbgl::underlying_type(Property::CircleStrokeWidth)}, + {"circle-translate", mbgl::underlying_type(Property::CircleTranslate)}, + {"circle-translate-anchor", mbgl::underlying_type(Property::CircleTranslateAnchor)}, + {"circle-blur-transition", mbgl::underlying_type(Property::CircleBlurTransition)}, + {"circle-color-transition", mbgl::underlying_type(Property::CircleColorTransition)}, + {"circle-opacity-transition", mbgl::underlying_type(Property::CircleOpacityTransition)}, + {"circle-pitch-alignment-transition", mbgl::underlying_type(Property::CirclePitchAlignmentTransition)}, + {"circle-pitch-scale-transition", mbgl::underlying_type(Property::CirclePitchScaleTransition)}, + {"circle-radius-transition", mbgl::underlying_type(Property::CircleRadiusTransition)}, + {"circle-stroke-color-transition", mbgl::underlying_type(Property::CircleStrokeColorTransition)}, + {"circle-stroke-opacity-transition", mbgl::underlying_type(Property::CircleStrokeOpacityTransition)}, + {"circle-stroke-width-transition", mbgl::underlying_type(Property::CircleStrokeWidthTransition)}, + {"circle-translate-transition", mbgl::underlying_type(Property::CircleTranslateTransition)}, + {"circle-translate-anchor-transition", mbgl::underlying_type(Property::CircleTranslateAnchorTransition)}}); + +} // namespace + optional CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - CircleBlur, - CircleColor, - CircleOpacity, - CirclePitchAlignment, - CirclePitchScale, - CircleRadius, - CircleStrokeColor, - CircleStrokeOpacity, - CircleStrokeWidth, - CircleTranslate, - CircleTranslateAnchor, - CircleBlurTransition, - CircleColorTransition, - CircleOpacityTransition, - CirclePitchAlignmentTransition, - CirclePitchScaleTransition, - CircleRadiusTransition, - CircleStrokeColorTransition, - CircleStrokeOpacityTransition, - CircleStrokeWidthTransition, - CircleTranslateTransition, - CircleTranslateAnchorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "circle-blur", mbgl::underlying_type(Property::CircleBlur) }, - { "circle-color", mbgl::underlying_type(Property::CircleColor) }, - { "circle-opacity", mbgl::underlying_type(Property::CircleOpacity) }, - { "circle-pitch-alignment", mbgl::underlying_type(Property::CirclePitchAlignment) }, - { "circle-pitch-scale", mbgl::underlying_type(Property::CirclePitchScale) }, - { "circle-radius", mbgl::underlying_type(Property::CircleRadius) }, - { "circle-stroke-color", mbgl::underlying_type(Property::CircleStrokeColor) }, - { "circle-stroke-opacity", mbgl::underlying_type(Property::CircleStrokeOpacity) }, - { "circle-stroke-width", mbgl::underlying_type(Property::CircleStrokeWidth) }, - { "circle-translate", mbgl::underlying_type(Property::CircleTranslate) }, - { "circle-translate-anchor", mbgl::underlying_type(Property::CircleTranslateAnchor) }, - { "circle-blur-transition", mbgl::underlying_type(Property::CircleBlurTransition) }, - { "circle-color-transition", mbgl::underlying_type(Property::CircleColorTransition) }, - { "circle-opacity-transition", mbgl::underlying_type(Property::CircleOpacityTransition) }, - { "circle-pitch-alignment-transition", mbgl::underlying_type(Property::CirclePitchAlignmentTransition) }, - { "circle-pitch-scale-transition", mbgl::underlying_type(Property::CirclePitchScaleTransition) }, - { "circle-radius-transition", mbgl::underlying_type(Property::CircleRadiusTransition) }, - { "circle-stroke-color-transition", mbgl::underlying_type(Property::CircleStrokeColorTransition) }, - { "circle-stroke-opacity-transition", mbgl::underlying_type(Property::CircleStrokeOpacityTransition) }, - { "circle-stroke-width-transition", mbgl::underlying_type(Property::CircleStrokeWidthTransition) }, - { "circle-translate-transition", mbgl::underlying_type(Property::CircleTranslateTransition) }, - { "circle-translate-anchor-transition", mbgl::underlying_type(Property::CircleTranslateAnchorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -590,6 +593,61 @@ optional CircleLayer::setPaintProperty(const std::string& name, const Con return Error { "layer doesn't support this property" }; } +LayerProperty CircleLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::CircleBlur: + return conversion::makeLayerProperty(getCircleBlur()); + case Property::CircleColor: + return conversion::makeLayerProperty(getCircleColor()); + case Property::CircleOpacity: + return conversion::makeLayerProperty(getCircleOpacity()); + case Property::CirclePitchAlignment: + return conversion::makeLayerProperty(getCirclePitchAlignment()); + case Property::CirclePitchScale: + return conversion::makeLayerProperty(getCirclePitchScale()); + case Property::CircleRadius: + return conversion::makeLayerProperty(getCircleRadius()); + case Property::CircleStrokeColor: + return conversion::makeLayerProperty(getCircleStrokeColor()); + case Property::CircleStrokeOpacity: + return conversion::makeLayerProperty(getCircleStrokeOpacity()); + case Property::CircleStrokeWidth: + return conversion::makeLayerProperty(getCircleStrokeWidth()); + case Property::CircleTranslate: + return conversion::makeLayerProperty(getCircleTranslate()); + case Property::CircleTranslateAnchor: + return conversion::makeLayerProperty(getCircleTranslateAnchor()); + case Property::CircleBlurTransition: + return conversion::makeLayerProperty(getCircleBlurTransition()); + case Property::CircleColorTransition: + return conversion::makeLayerProperty(getCircleColorTransition()); + case Property::CircleOpacityTransition: + return conversion::makeLayerProperty(getCircleOpacityTransition()); + case Property::CirclePitchAlignmentTransition: + return conversion::makeLayerProperty(getCirclePitchAlignmentTransition()); + case Property::CirclePitchScaleTransition: + return conversion::makeLayerProperty(getCirclePitchScaleTransition()); + case Property::CircleRadiusTransition: + return conversion::makeLayerProperty(getCircleRadiusTransition()); + case Property::CircleStrokeColorTransition: + return conversion::makeLayerProperty(getCircleStrokeColorTransition()); + case Property::CircleStrokeOpacityTransition: + return conversion::makeLayerProperty(getCircleStrokeOpacityTransition()); + case Property::CircleStrokeWidthTransition: + return conversion::makeLayerProperty(getCircleStrokeWidthTransition()); + case Property::CircleTranslateTransition: + return conversion::makeLayerProperty(getCircleTranslateTransition()); + case Property::CircleTranslateAnchorTransition: + return conversion::makeLayerProperty(getCircleTranslateAnchorTransition()); + } + return {}; +} + optional CircleLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index 8b9e17ea25..f96cc682e5 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -47,6 +47,10 @@ optional CustomLayer::setLayoutProperty(const std::string&, const Convert return Error { "layer doesn't support this property" }; } +LayerProperty CustomLayer::getPaintProperty(const std::string&) const { + return {}; +} + Mutable CustomLayer::mutableBaseImpl() const { return staticMutableCast(mutableImpl()); } diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 2686f7d044..43183255a1 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -283,47 +283,50 @@ TransitionOptions FillExtrusionLayer::getFillExtrusionVerticalGradientTransition using namespace conversion; +namespace { + +enum class Property { + FillExtrusionBase, + FillExtrusionColor, + FillExtrusionHeight, + FillExtrusionOpacity, + FillExtrusionPattern, + FillExtrusionTranslate, + FillExtrusionTranslateAnchor, + FillExtrusionVerticalGradient, + FillExtrusionBaseTransition, + FillExtrusionColorTransition, + FillExtrusionHeightTransition, + FillExtrusionOpacityTransition, + FillExtrusionPatternTransition, + FillExtrusionTranslateTransition, + FillExtrusionTranslateAnchorTransition, + FillExtrusionVerticalGradientTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"fill-extrusion-base", mbgl::underlying_type(Property::FillExtrusionBase)}, + {"fill-extrusion-color", mbgl::underlying_type(Property::FillExtrusionColor)}, + {"fill-extrusion-height", mbgl::underlying_type(Property::FillExtrusionHeight)}, + {"fill-extrusion-opacity", mbgl::underlying_type(Property::FillExtrusionOpacity)}, + {"fill-extrusion-pattern", mbgl::underlying_type(Property::FillExtrusionPattern)}, + {"fill-extrusion-translate", mbgl::underlying_type(Property::FillExtrusionTranslate)}, + {"fill-extrusion-translate-anchor", mbgl::underlying_type(Property::FillExtrusionTranslateAnchor)}, + {"fill-extrusion-vertical-gradient", mbgl::underlying_type(Property::FillExtrusionVerticalGradient)}, + {"fill-extrusion-base-transition", mbgl::underlying_type(Property::FillExtrusionBaseTransition)}, + {"fill-extrusion-color-transition", mbgl::underlying_type(Property::FillExtrusionColorTransition)}, + {"fill-extrusion-height-transition", mbgl::underlying_type(Property::FillExtrusionHeightTransition)}, + {"fill-extrusion-opacity-transition", mbgl::underlying_type(Property::FillExtrusionOpacityTransition)}, + {"fill-extrusion-pattern-transition", mbgl::underlying_type(Property::FillExtrusionPatternTransition)}, + {"fill-extrusion-translate-transition", mbgl::underlying_type(Property::FillExtrusionTranslateTransition)}, + {"fill-extrusion-translate-anchor-transition", mbgl::underlying_type(Property::FillExtrusionTranslateAnchorTransition)}, + {"fill-extrusion-vertical-gradient-transition", mbgl::underlying_type(Property::FillExtrusionVerticalGradientTransition)}}); + +} // namespace + optional FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - FillExtrusionBase, - FillExtrusionColor, - FillExtrusionHeight, - FillExtrusionOpacity, - FillExtrusionPattern, - FillExtrusionTranslate, - FillExtrusionTranslateAnchor, - FillExtrusionVerticalGradient, - FillExtrusionBaseTransition, - FillExtrusionColorTransition, - FillExtrusionHeightTransition, - FillExtrusionOpacityTransition, - FillExtrusionPatternTransition, - FillExtrusionTranslateTransition, - FillExtrusionTranslateAnchorTransition, - FillExtrusionVerticalGradientTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "fill-extrusion-base", mbgl::underlying_type(Property::FillExtrusionBase) }, - { "fill-extrusion-color", mbgl::underlying_type(Property::FillExtrusionColor) }, - { "fill-extrusion-height", mbgl::underlying_type(Property::FillExtrusionHeight) }, - { "fill-extrusion-opacity", mbgl::underlying_type(Property::FillExtrusionOpacity) }, - { "fill-extrusion-pattern", mbgl::underlying_type(Property::FillExtrusionPattern) }, - { "fill-extrusion-translate", mbgl::underlying_type(Property::FillExtrusionTranslate) }, - { "fill-extrusion-translate-anchor", mbgl::underlying_type(Property::FillExtrusionTranslateAnchor) }, - { "fill-extrusion-vertical-gradient", mbgl::underlying_type(Property::FillExtrusionVerticalGradient) }, - { "fill-extrusion-base-transition", mbgl::underlying_type(Property::FillExtrusionBaseTransition) }, - { "fill-extrusion-color-transition", mbgl::underlying_type(Property::FillExtrusionColorTransition) }, - { "fill-extrusion-height-transition", mbgl::underlying_type(Property::FillExtrusionHeightTransition) }, - { "fill-extrusion-opacity-transition", mbgl::underlying_type(Property::FillExtrusionOpacityTransition) }, - { "fill-extrusion-pattern-transition", mbgl::underlying_type(Property::FillExtrusionPatternTransition) }, - { "fill-extrusion-translate-transition", mbgl::underlying_type(Property::FillExtrusionTranslateTransition) }, - { "fill-extrusion-translate-anchor-transition", mbgl::underlying_type(Property::FillExtrusionTranslateAnchorTransition) }, - { "fill-extrusion-vertical-gradient-transition", mbgl::underlying_type(Property::FillExtrusionVerticalGradientTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -472,6 +475,49 @@ optional FillExtrusionLayer::setPaintProperty(const std::string& name, co return Error { "layer doesn't support this property" }; } +LayerProperty FillExtrusionLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::FillExtrusionBase: + return conversion::makeLayerProperty(getFillExtrusionBase()); + case Property::FillExtrusionColor: + return conversion::makeLayerProperty(getFillExtrusionColor()); + case Property::FillExtrusionHeight: + return conversion::makeLayerProperty(getFillExtrusionHeight()); + case Property::FillExtrusionOpacity: + return conversion::makeLayerProperty(getFillExtrusionOpacity()); + case Property::FillExtrusionPattern: + return conversion::makeLayerProperty(getFillExtrusionPattern()); + case Property::FillExtrusionTranslate: + return conversion::makeLayerProperty(getFillExtrusionTranslate()); + case Property::FillExtrusionTranslateAnchor: + return conversion::makeLayerProperty(getFillExtrusionTranslateAnchor()); + case Property::FillExtrusionVerticalGradient: + return conversion::makeLayerProperty(getFillExtrusionVerticalGradient()); + case Property::FillExtrusionBaseTransition: + return conversion::makeLayerProperty(getFillExtrusionBaseTransition()); + case Property::FillExtrusionColorTransition: + return conversion::makeLayerProperty(getFillExtrusionColorTransition()); + case Property::FillExtrusionHeightTransition: + return conversion::makeLayerProperty(getFillExtrusionHeightTransition()); + case Property::FillExtrusionOpacityTransition: + return conversion::makeLayerProperty(getFillExtrusionOpacityTransition()); + case Property::FillExtrusionPatternTransition: + return conversion::makeLayerProperty(getFillExtrusionPatternTransition()); + case Property::FillExtrusionTranslateTransition: + return conversion::makeLayerProperty(getFillExtrusionTranslateTransition()); + case Property::FillExtrusionTranslateAnchorTransition: + return conversion::makeLayerProperty(getFillExtrusionTranslateAnchorTransition()); + case Property::FillExtrusionVerticalGradientTransition: + return conversion::makeLayerProperty(getFillExtrusionVerticalGradientTransition()); + } + return {}; +} + optional FillExtrusionLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 52f2b166b3..9afc99d1d3 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -256,43 +256,46 @@ TransitionOptions FillLayer::getFillTranslateAnchorTransition() const { using namespace conversion; +namespace { + +enum class Property { + FillAntialias, + FillColor, + FillOpacity, + FillOutlineColor, + FillPattern, + FillTranslate, + FillTranslateAnchor, + FillAntialiasTransition, + FillColorTransition, + FillOpacityTransition, + FillOutlineColorTransition, + FillPatternTransition, + FillTranslateTransition, + FillTranslateAnchorTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"fill-antialias", mbgl::underlying_type(Property::FillAntialias)}, + {"fill-color", mbgl::underlying_type(Property::FillColor)}, + {"fill-opacity", mbgl::underlying_type(Property::FillOpacity)}, + {"fill-outline-color", mbgl::underlying_type(Property::FillOutlineColor)}, + {"fill-pattern", mbgl::underlying_type(Property::FillPattern)}, + {"fill-translate", mbgl::underlying_type(Property::FillTranslate)}, + {"fill-translate-anchor", mbgl::underlying_type(Property::FillTranslateAnchor)}, + {"fill-antialias-transition", mbgl::underlying_type(Property::FillAntialiasTransition)}, + {"fill-color-transition", mbgl::underlying_type(Property::FillColorTransition)}, + {"fill-opacity-transition", mbgl::underlying_type(Property::FillOpacityTransition)}, + {"fill-outline-color-transition", mbgl::underlying_type(Property::FillOutlineColorTransition)}, + {"fill-pattern-transition", mbgl::underlying_type(Property::FillPatternTransition)}, + {"fill-translate-transition", mbgl::underlying_type(Property::FillTranslateTransition)}, + {"fill-translate-anchor-transition", mbgl::underlying_type(Property::FillTranslateAnchorTransition)}}); + +} // namespace + optional FillLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - FillAntialias, - FillColor, - FillOpacity, - FillOutlineColor, - FillPattern, - FillTranslate, - FillTranslateAnchor, - FillAntialiasTransition, - FillColorTransition, - FillOpacityTransition, - FillOutlineColorTransition, - FillPatternTransition, - FillTranslateTransition, - FillTranslateAnchorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "fill-antialias", mbgl::underlying_type(Property::FillAntialias) }, - { "fill-color", mbgl::underlying_type(Property::FillColor) }, - { "fill-opacity", mbgl::underlying_type(Property::FillOpacity) }, - { "fill-outline-color", mbgl::underlying_type(Property::FillOutlineColor) }, - { "fill-pattern", mbgl::underlying_type(Property::FillPattern) }, - { "fill-translate", mbgl::underlying_type(Property::FillTranslate) }, - { "fill-translate-anchor", mbgl::underlying_type(Property::FillTranslateAnchor) }, - { "fill-antialias-transition", mbgl::underlying_type(Property::FillAntialiasTransition) }, - { "fill-color-transition", mbgl::underlying_type(Property::FillColorTransition) }, - { "fill-opacity-transition", mbgl::underlying_type(Property::FillOpacityTransition) }, - { "fill-outline-color-transition", mbgl::underlying_type(Property::FillOutlineColorTransition) }, - { "fill-pattern-transition", mbgl::underlying_type(Property::FillPatternTransition) }, - { "fill-translate-transition", mbgl::underlying_type(Property::FillTranslateTransition) }, - { "fill-translate-anchor-transition", mbgl::underlying_type(Property::FillTranslateAnchorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -424,6 +427,45 @@ optional FillLayer::setPaintProperty(const std::string& name, const Conve return Error { "layer doesn't support this property" }; } +LayerProperty FillLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::FillAntialias: + return conversion::makeLayerProperty(getFillAntialias()); + case Property::FillColor: + return conversion::makeLayerProperty(getFillColor()); + case Property::FillOpacity: + return conversion::makeLayerProperty(getFillOpacity()); + case Property::FillOutlineColor: + return conversion::makeLayerProperty(getFillOutlineColor()); + case Property::FillPattern: + return conversion::makeLayerProperty(getFillPattern()); + case Property::FillTranslate: + return conversion::makeLayerProperty(getFillTranslate()); + case Property::FillTranslateAnchor: + return conversion::makeLayerProperty(getFillTranslateAnchor()); + case Property::FillAntialiasTransition: + return conversion::makeLayerProperty(getFillAntialiasTransition()); + case Property::FillColorTransition: + return conversion::makeLayerProperty(getFillColorTransition()); + case Property::FillOpacityTransition: + return conversion::makeLayerProperty(getFillOpacityTransition()); + case Property::FillOutlineColorTransition: + return conversion::makeLayerProperty(getFillOutlineColorTransition()); + case Property::FillPatternTransition: + return conversion::makeLayerProperty(getFillPatternTransition()); + case Property::FillTranslateTransition: + return conversion::makeLayerProperty(getFillTranslateTransition()); + case Property::FillTranslateAnchorTransition: + return conversion::makeLayerProperty(getFillTranslateAnchorTransition()); + } + return {}; +} + optional FillLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 86bb2d6de1..417e828a1d 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -204,35 +204,38 @@ TransitionOptions HeatmapLayer::getHeatmapWeightTransition() const { using namespace conversion; +namespace { + +enum class Property { + HeatmapColor, + HeatmapIntensity, + HeatmapOpacity, + HeatmapRadius, + HeatmapWeight, + HeatmapColorTransition, + HeatmapIntensityTransition, + HeatmapOpacityTransition, + HeatmapRadiusTransition, + HeatmapWeightTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"heatmap-color", mbgl::underlying_type(Property::HeatmapColor)}, + {"heatmap-intensity", mbgl::underlying_type(Property::HeatmapIntensity)}, + {"heatmap-opacity", mbgl::underlying_type(Property::HeatmapOpacity)}, + {"heatmap-radius", mbgl::underlying_type(Property::HeatmapRadius)}, + {"heatmap-weight", mbgl::underlying_type(Property::HeatmapWeight)}, + {"heatmap-color-transition", mbgl::underlying_type(Property::HeatmapColorTransition)}, + {"heatmap-intensity-transition", mbgl::underlying_type(Property::HeatmapIntensityTransition)}, + {"heatmap-opacity-transition", mbgl::underlying_type(Property::HeatmapOpacityTransition)}, + {"heatmap-radius-transition", mbgl::underlying_type(Property::HeatmapRadiusTransition)}, + {"heatmap-weight-transition", mbgl::underlying_type(Property::HeatmapWeightTransition)}}); + +} // namespace + optional HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - HeatmapColor, - HeatmapIntensity, - HeatmapOpacity, - HeatmapRadius, - HeatmapWeight, - HeatmapColorTransition, - HeatmapIntensityTransition, - HeatmapOpacityTransition, - HeatmapRadiusTransition, - HeatmapWeightTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "heatmap-color", mbgl::underlying_type(Property::HeatmapColor) }, - { "heatmap-intensity", mbgl::underlying_type(Property::HeatmapIntensity) }, - { "heatmap-opacity", mbgl::underlying_type(Property::HeatmapOpacity) }, - { "heatmap-radius", mbgl::underlying_type(Property::HeatmapRadius) }, - { "heatmap-weight", mbgl::underlying_type(Property::HeatmapWeight) }, - { "heatmap-color-transition", mbgl::underlying_type(Property::HeatmapColorTransition) }, - { "heatmap-intensity-transition", mbgl::underlying_type(Property::HeatmapIntensityTransition) }, - { "heatmap-opacity-transition", mbgl::underlying_type(Property::HeatmapOpacityTransition) }, - { "heatmap-radius-transition", mbgl::underlying_type(Property::HeatmapRadiusTransition) }, - { "heatmap-weight-transition", mbgl::underlying_type(Property::HeatmapWeightTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -325,6 +328,37 @@ optional HeatmapLayer::setPaintProperty(const std::string& name, const Co return Error { "layer doesn't support this property" }; } +LayerProperty HeatmapLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::HeatmapColor: + return conversion::makeLayerProperty(getHeatmapColor()); + case Property::HeatmapIntensity: + return conversion::makeLayerProperty(getHeatmapIntensity()); + case Property::HeatmapOpacity: + return conversion::makeLayerProperty(getHeatmapOpacity()); + case Property::HeatmapRadius: + return conversion::makeLayerProperty(getHeatmapRadius()); + case Property::HeatmapWeight: + return conversion::makeLayerProperty(getHeatmapWeight()); + case Property::HeatmapColorTransition: + return conversion::makeLayerProperty(getHeatmapColorTransition()); + case Property::HeatmapIntensityTransition: + return conversion::makeLayerProperty(getHeatmapIntensityTransition()); + case Property::HeatmapOpacityTransition: + return conversion::makeLayerProperty(getHeatmapOpacityTransition()); + case Property::HeatmapRadiusTransition: + return conversion::makeLayerProperty(getHeatmapRadiusTransition()); + case Property::HeatmapWeightTransition: + return conversion::makeLayerProperty(getHeatmapWeightTransition()); + } + return {}; +} + optional HeatmapLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 710efe5844..60ef4d33f1 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -229,39 +229,42 @@ TransitionOptions HillshadeLayer::getHillshadeShadowColorTransition() const { using namespace conversion; +namespace { + +enum class Property { + HillshadeAccentColor, + HillshadeExaggeration, + HillshadeHighlightColor, + HillshadeIlluminationAnchor, + HillshadeIlluminationDirection, + HillshadeShadowColor, + HillshadeAccentColorTransition, + HillshadeExaggerationTransition, + HillshadeHighlightColorTransition, + HillshadeIlluminationAnchorTransition, + HillshadeIlluminationDirectionTransition, + HillshadeShadowColorTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"hillshade-accent-color", mbgl::underlying_type(Property::HillshadeAccentColor)}, + {"hillshade-exaggeration", mbgl::underlying_type(Property::HillshadeExaggeration)}, + {"hillshade-highlight-color", mbgl::underlying_type(Property::HillshadeHighlightColor)}, + {"hillshade-illumination-anchor", mbgl::underlying_type(Property::HillshadeIlluminationAnchor)}, + {"hillshade-illumination-direction", mbgl::underlying_type(Property::HillshadeIlluminationDirection)}, + {"hillshade-shadow-color", mbgl::underlying_type(Property::HillshadeShadowColor)}, + {"hillshade-accent-color-transition", mbgl::underlying_type(Property::HillshadeAccentColorTransition)}, + {"hillshade-exaggeration-transition", mbgl::underlying_type(Property::HillshadeExaggerationTransition)}, + {"hillshade-highlight-color-transition", mbgl::underlying_type(Property::HillshadeHighlightColorTransition)}, + {"hillshade-illumination-anchor-transition", mbgl::underlying_type(Property::HillshadeIlluminationAnchorTransition)}, + {"hillshade-illumination-direction-transition", mbgl::underlying_type(Property::HillshadeIlluminationDirectionTransition)}, + {"hillshade-shadow-color-transition", mbgl::underlying_type(Property::HillshadeShadowColorTransition)}}); + +} // namespace + optional HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - HillshadeAccentColor, - HillshadeExaggeration, - HillshadeHighlightColor, - HillshadeIlluminationAnchor, - HillshadeIlluminationDirection, - HillshadeShadowColor, - HillshadeAccentColorTransition, - HillshadeExaggerationTransition, - HillshadeHighlightColorTransition, - HillshadeIlluminationAnchorTransition, - HillshadeIlluminationDirectionTransition, - HillshadeShadowColorTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "hillshade-accent-color", mbgl::underlying_type(Property::HillshadeAccentColor) }, - { "hillshade-exaggeration", mbgl::underlying_type(Property::HillshadeExaggeration) }, - { "hillshade-highlight-color", mbgl::underlying_type(Property::HillshadeHighlightColor) }, - { "hillshade-illumination-anchor", mbgl::underlying_type(Property::HillshadeIlluminationAnchor) }, - { "hillshade-illumination-direction", mbgl::underlying_type(Property::HillshadeIlluminationDirection) }, - { "hillshade-shadow-color", mbgl::underlying_type(Property::HillshadeShadowColor) }, - { "hillshade-accent-color-transition", mbgl::underlying_type(Property::HillshadeAccentColorTransition) }, - { "hillshade-exaggeration-transition", mbgl::underlying_type(Property::HillshadeExaggerationTransition) }, - { "hillshade-highlight-color-transition", mbgl::underlying_type(Property::HillshadeHighlightColorTransition) }, - { "hillshade-illumination-anchor-transition", mbgl::underlying_type(Property::HillshadeIlluminationAnchorTransition) }, - { "hillshade-illumination-direction-transition", mbgl::underlying_type(Property::HillshadeIlluminationDirectionTransition) }, - { "hillshade-shadow-color-transition", mbgl::underlying_type(Property::HillshadeShadowColorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -364,6 +367,41 @@ optional HillshadeLayer::setPaintProperty(const std::string& name, const return Error { "layer doesn't support this property" }; } +LayerProperty HillshadeLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::HillshadeAccentColor: + return conversion::makeLayerProperty(getHillshadeAccentColor()); + case Property::HillshadeExaggeration: + return conversion::makeLayerProperty(getHillshadeExaggeration()); + case Property::HillshadeHighlightColor: + return conversion::makeLayerProperty(getHillshadeHighlightColor()); + case Property::HillshadeIlluminationAnchor: + return conversion::makeLayerProperty(getHillshadeIlluminationAnchor()); + case Property::HillshadeIlluminationDirection: + return conversion::makeLayerProperty(getHillshadeIlluminationDirection()); + case Property::HillshadeShadowColor: + return conversion::makeLayerProperty(getHillshadeShadowColor()); + case Property::HillshadeAccentColorTransition: + return conversion::makeLayerProperty(getHillshadeAccentColorTransition()); + case Property::HillshadeExaggerationTransition: + return conversion::makeLayerProperty(getHillshadeExaggerationTransition()); + case Property::HillshadeHighlightColorTransition: + return conversion::makeLayerProperty(getHillshadeHighlightColorTransition()); + case Property::HillshadeIlluminationAnchorTransition: + return conversion::makeLayerProperty(getHillshadeIlluminationAnchorTransition()); + case Property::HillshadeIlluminationDirectionTransition: + return conversion::makeLayerProperty(getHillshadeIlluminationDirectionTransition()); + case Property::HillshadeShadowColorTransition: + return conversion::makeLayerProperty(getHillshadeShadowColorTransition()); + } + return {}; +} + optional HillshadeLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 0cd9a82d75..04d4a81dce 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -190,23 +190,26 @@ TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>T using namespace conversion; -optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { +namespace { + +enum class Property { <% for (const property of paintProperties) { -%> - <%- camelize(property.name) %>, + <%- camelize(property.name) %>, <% } -%> <% for (const property of paintProperties) { -%> - <%- camelize(property.name) %>Transition, + <%- camelize(property.name) %>Transition, <% } -%> - }; +}; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - <%- paintProperties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>, - <%- paintProperties.map(p => `{ "${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition) }`).join(',\n ') %> - }); +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {<%- paintProperties.map(p => `{"${p.name}", mbgl::underlying_type(Property::${camelize(p.name)})}`).join(',\n ') %>, + <%- paintProperties.map(p => `{"${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { +} // namespace + +optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -258,6 +261,25 @@ optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& return Error { "layer doesn't support this property" }; } +LayerProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { +<% for (const property of paintProperties) { -%> + case Property::<%- camelize(property.name) %>: + return conversion::makeLayerProperty(get<%- camelize(property.name) %>()); +<% } -%> +<% for (const property of paintProperties) { -%> + case Property::<%- camelize(property.name) %>Transition: + return conversion::makeLayerProperty(get<%- camelize(property.name) %>Transition()); +<% } -%> + } + return {}; +} + optional <%- camelize(type) %>Layer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index bd29f7f6fd..491cfd48a0 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -430,59 +430,62 @@ TransitionOptions LineLayer::getLineWidthTransition() const { using namespace conversion; -optional LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - LineBlur, - LineColor, - LineDasharray, - LineGapWidth, - LineGradient, - LineOffset, - LineOpacity, - LinePattern, - LineTranslate, - LineTranslateAnchor, - LineWidth, - LineBlurTransition, - LineColorTransition, - LineDasharrayTransition, - LineGapWidthTransition, - LineGradientTransition, - LineOffsetTransition, - LineOpacityTransition, - LinePatternTransition, - LineTranslateTransition, - LineTranslateAnchorTransition, - LineWidthTransition, - }; +namespace { + +enum class Property { + LineBlur, + LineColor, + LineDasharray, + LineGapWidth, + LineGradient, + LineOffset, + LineOpacity, + LinePattern, + LineTranslate, + LineTranslateAnchor, + LineWidth, + LineBlurTransition, + LineColorTransition, + LineDasharrayTransition, + LineGapWidthTransition, + LineGradientTransition, + LineOffsetTransition, + LineOpacityTransition, + LinePatternTransition, + LineTranslateTransition, + LineTranslateAnchorTransition, + LineWidthTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"line-blur", mbgl::underlying_type(Property::LineBlur)}, + {"line-color", mbgl::underlying_type(Property::LineColor)}, + {"line-dasharray", mbgl::underlying_type(Property::LineDasharray)}, + {"line-gap-width", mbgl::underlying_type(Property::LineGapWidth)}, + {"line-gradient", mbgl::underlying_type(Property::LineGradient)}, + {"line-offset", mbgl::underlying_type(Property::LineOffset)}, + {"line-opacity", mbgl::underlying_type(Property::LineOpacity)}, + {"line-pattern", mbgl::underlying_type(Property::LinePattern)}, + {"line-translate", mbgl::underlying_type(Property::LineTranslate)}, + {"line-translate-anchor", mbgl::underlying_type(Property::LineTranslateAnchor)}, + {"line-width", mbgl::underlying_type(Property::LineWidth)}, + {"line-blur-transition", mbgl::underlying_type(Property::LineBlurTransition)}, + {"line-color-transition", mbgl::underlying_type(Property::LineColorTransition)}, + {"line-dasharray-transition", mbgl::underlying_type(Property::LineDasharrayTransition)}, + {"line-gap-width-transition", mbgl::underlying_type(Property::LineGapWidthTransition)}, + {"line-gradient-transition", mbgl::underlying_type(Property::LineGradientTransition)}, + {"line-offset-transition", mbgl::underlying_type(Property::LineOffsetTransition)}, + {"line-opacity-transition", mbgl::underlying_type(Property::LineOpacityTransition)}, + {"line-pattern-transition", mbgl::underlying_type(Property::LinePatternTransition)}, + {"line-translate-transition", mbgl::underlying_type(Property::LineTranslateTransition)}, + {"line-translate-anchor-transition", mbgl::underlying_type(Property::LineTranslateAnchorTransition)}, + {"line-width-transition", mbgl::underlying_type(Property::LineWidthTransition)}}); + +} // namespace - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "line-blur", mbgl::underlying_type(Property::LineBlur) }, - { "line-color", mbgl::underlying_type(Property::LineColor) }, - { "line-dasharray", mbgl::underlying_type(Property::LineDasharray) }, - { "line-gap-width", mbgl::underlying_type(Property::LineGapWidth) }, - { "line-gradient", mbgl::underlying_type(Property::LineGradient) }, - { "line-offset", mbgl::underlying_type(Property::LineOffset) }, - { "line-opacity", mbgl::underlying_type(Property::LineOpacity) }, - { "line-pattern", mbgl::underlying_type(Property::LinePattern) }, - { "line-translate", mbgl::underlying_type(Property::LineTranslate) }, - { "line-translate-anchor", mbgl::underlying_type(Property::LineTranslateAnchor) }, - { "line-width", mbgl::underlying_type(Property::LineWidth) }, - { "line-blur-transition", mbgl::underlying_type(Property::LineBlurTransition) }, - { "line-color-transition", mbgl::underlying_type(Property::LineColorTransition) }, - { "line-dasharray-transition", mbgl::underlying_type(Property::LineDasharrayTransition) }, - { "line-gap-width-transition", mbgl::underlying_type(Property::LineGapWidthTransition) }, - { "line-gradient-transition", mbgl::underlying_type(Property::LineGradientTransition) }, - { "line-offset-transition", mbgl::underlying_type(Property::LineOffsetTransition) }, - { "line-opacity-transition", mbgl::underlying_type(Property::LineOpacityTransition) }, - { "line-pattern-transition", mbgl::underlying_type(Property::LinePatternTransition) }, - { "line-translate-transition", mbgl::underlying_type(Property::LineTranslateTransition) }, - { "line-translate-anchor-transition", mbgl::underlying_type(Property::LineTranslateAnchorTransition) }, - { "line-width-transition", mbgl::underlying_type(Property::LineWidthTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { +optional LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -661,6 +664,61 @@ optional LineLayer::setPaintProperty(const std::string& name, const Conve return Error { "layer doesn't support this property" }; } +LayerProperty LineLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::LineBlur: + return conversion::makeLayerProperty(getLineBlur()); + case Property::LineColor: + return conversion::makeLayerProperty(getLineColor()); + case Property::LineDasharray: + return conversion::makeLayerProperty(getLineDasharray()); + case Property::LineGapWidth: + return conversion::makeLayerProperty(getLineGapWidth()); + case Property::LineGradient: + return conversion::makeLayerProperty(getLineGradient()); + case Property::LineOffset: + return conversion::makeLayerProperty(getLineOffset()); + case Property::LineOpacity: + return conversion::makeLayerProperty(getLineOpacity()); + case Property::LinePattern: + return conversion::makeLayerProperty(getLinePattern()); + case Property::LineTranslate: + return conversion::makeLayerProperty(getLineTranslate()); + case Property::LineTranslateAnchor: + return conversion::makeLayerProperty(getLineTranslateAnchor()); + case Property::LineWidth: + return conversion::makeLayerProperty(getLineWidth()); + case Property::LineBlurTransition: + return conversion::makeLayerProperty(getLineBlurTransition()); + case Property::LineColorTransition: + return conversion::makeLayerProperty(getLineColorTransition()); + case Property::LineDasharrayTransition: + return conversion::makeLayerProperty(getLineDasharrayTransition()); + case Property::LineGapWidthTransition: + return conversion::makeLayerProperty(getLineGapWidthTransition()); + case Property::LineGradientTransition: + return conversion::makeLayerProperty(getLineGradientTransition()); + case Property::LineOffsetTransition: + return conversion::makeLayerProperty(getLineOffsetTransition()); + case Property::LineOpacityTransition: + return conversion::makeLayerProperty(getLineOpacityTransition()); + case Property::LinePatternTransition: + return conversion::makeLayerProperty(getLinePatternTransition()); + case Property::LineTranslateTransition: + return conversion::makeLayerProperty(getLineTranslateTransition()); + case Property::LineTranslateAnchorTransition: + return conversion::makeLayerProperty(getLineTranslateAnchorTransition()); + case Property::LineWidthTransition: + return conversion::makeLayerProperty(getLineWidthTransition()); + } + return {}; +} + optional LineLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index fde1df838d..d10ba0ae8e 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -283,47 +283,50 @@ TransitionOptions RasterLayer::getRasterSaturationTransition() const { using namespace conversion; +namespace { + +enum class Property { + RasterBrightnessMax, + RasterBrightnessMin, + RasterContrast, + RasterFadeDuration, + RasterHueRotate, + RasterOpacity, + RasterResampling, + RasterSaturation, + RasterBrightnessMaxTransition, + RasterBrightnessMinTransition, + RasterContrastTransition, + RasterFadeDurationTransition, + RasterHueRotateTransition, + RasterOpacityTransition, + RasterResamplingTransition, + RasterSaturationTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"raster-brightness-max", mbgl::underlying_type(Property::RasterBrightnessMax)}, + {"raster-brightness-min", mbgl::underlying_type(Property::RasterBrightnessMin)}, + {"raster-contrast", mbgl::underlying_type(Property::RasterContrast)}, + {"raster-fade-duration", mbgl::underlying_type(Property::RasterFadeDuration)}, + {"raster-hue-rotate", mbgl::underlying_type(Property::RasterHueRotate)}, + {"raster-opacity", mbgl::underlying_type(Property::RasterOpacity)}, + {"raster-resampling", mbgl::underlying_type(Property::RasterResampling)}, + {"raster-saturation", mbgl::underlying_type(Property::RasterSaturation)}, + {"raster-brightness-max-transition", mbgl::underlying_type(Property::RasterBrightnessMaxTransition)}, + {"raster-brightness-min-transition", mbgl::underlying_type(Property::RasterBrightnessMinTransition)}, + {"raster-contrast-transition", mbgl::underlying_type(Property::RasterContrastTransition)}, + {"raster-fade-duration-transition", mbgl::underlying_type(Property::RasterFadeDurationTransition)}, + {"raster-hue-rotate-transition", mbgl::underlying_type(Property::RasterHueRotateTransition)}, + {"raster-opacity-transition", mbgl::underlying_type(Property::RasterOpacityTransition)}, + {"raster-resampling-transition", mbgl::underlying_type(Property::RasterResamplingTransition)}, + {"raster-saturation-transition", mbgl::underlying_type(Property::RasterSaturationTransition)}}); + +} // namespace + optional RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - RasterBrightnessMax, - RasterBrightnessMin, - RasterContrast, - RasterFadeDuration, - RasterHueRotate, - RasterOpacity, - RasterResampling, - RasterSaturation, - RasterBrightnessMaxTransition, - RasterBrightnessMinTransition, - RasterContrastTransition, - RasterFadeDurationTransition, - RasterHueRotateTransition, - RasterOpacityTransition, - RasterResamplingTransition, - RasterSaturationTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "raster-brightness-max", mbgl::underlying_type(Property::RasterBrightnessMax) }, - { "raster-brightness-min", mbgl::underlying_type(Property::RasterBrightnessMin) }, - { "raster-contrast", mbgl::underlying_type(Property::RasterContrast) }, - { "raster-fade-duration", mbgl::underlying_type(Property::RasterFadeDuration) }, - { "raster-hue-rotate", mbgl::underlying_type(Property::RasterHueRotate) }, - { "raster-opacity", mbgl::underlying_type(Property::RasterOpacity) }, - { "raster-resampling", mbgl::underlying_type(Property::RasterResampling) }, - { "raster-saturation", mbgl::underlying_type(Property::RasterSaturation) }, - { "raster-brightness-max-transition", mbgl::underlying_type(Property::RasterBrightnessMaxTransition) }, - { "raster-brightness-min-transition", mbgl::underlying_type(Property::RasterBrightnessMinTransition) }, - { "raster-contrast-transition", mbgl::underlying_type(Property::RasterContrastTransition) }, - { "raster-fade-duration-transition", mbgl::underlying_type(Property::RasterFadeDurationTransition) }, - { "raster-hue-rotate-transition", mbgl::underlying_type(Property::RasterHueRotateTransition) }, - { "raster-opacity-transition", mbgl::underlying_type(Property::RasterOpacityTransition) }, - { "raster-resampling-transition", mbgl::underlying_type(Property::RasterResamplingTransition) }, - { "raster-saturation-transition", mbgl::underlying_type(Property::RasterSaturationTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -437,6 +440,49 @@ optional RasterLayer::setPaintProperty(const std::string& name, const Con return Error { "layer doesn't support this property" }; } +LayerProperty RasterLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::RasterBrightnessMax: + return conversion::makeLayerProperty(getRasterBrightnessMax()); + case Property::RasterBrightnessMin: + return conversion::makeLayerProperty(getRasterBrightnessMin()); + case Property::RasterContrast: + return conversion::makeLayerProperty(getRasterContrast()); + case Property::RasterFadeDuration: + return conversion::makeLayerProperty(getRasterFadeDuration()); + case Property::RasterHueRotate: + return conversion::makeLayerProperty(getRasterHueRotate()); + case Property::RasterOpacity: + return conversion::makeLayerProperty(getRasterOpacity()); + case Property::RasterResampling: + return conversion::makeLayerProperty(getRasterResampling()); + case Property::RasterSaturation: + return conversion::makeLayerProperty(getRasterSaturation()); + case Property::RasterBrightnessMaxTransition: + return conversion::makeLayerProperty(getRasterBrightnessMaxTransition()); + case Property::RasterBrightnessMinTransition: + return conversion::makeLayerProperty(getRasterBrightnessMinTransition()); + case Property::RasterContrastTransition: + return conversion::makeLayerProperty(getRasterContrastTransition()); + case Property::RasterFadeDurationTransition: + return conversion::makeLayerProperty(getRasterFadeDurationTransition()); + case Property::RasterHueRotateTransition: + return conversion::makeLayerProperty(getRasterHueRotateTransition()); + case Property::RasterOpacityTransition: + return conversion::makeLayerProperty(getRasterOpacityTransition()); + case Property::RasterResamplingTransition: + return conversion::makeLayerProperty(getRasterResamplingTransition()); + case Property::RasterSaturationTransition: + return conversion::makeLayerProperty(getRasterSaturationTransition()); + } + return {}; +} + optional RasterLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index af5daa4dc0..b36c02e558 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1102,71 +1102,74 @@ TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const { using namespace conversion; -optional SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { - enum class Property { - IconColor, - IconHaloBlur, - IconHaloColor, - IconHaloWidth, - IconOpacity, - IconTranslate, - IconTranslateAnchor, - TextColor, - TextHaloBlur, - TextHaloColor, - TextHaloWidth, - TextOpacity, - TextTranslate, - TextTranslateAnchor, - IconColorTransition, - IconHaloBlurTransition, - IconHaloColorTransition, - IconHaloWidthTransition, - IconOpacityTransition, - IconTranslateTransition, - IconTranslateAnchorTransition, - TextColorTransition, - TextHaloBlurTransition, - TextHaloColorTransition, - TextHaloWidthTransition, - TextOpacityTransition, - TextTranslateTransition, - TextTranslateAnchorTransition, - }; +namespace { + +enum class Property { + IconColor, + IconHaloBlur, + IconHaloColor, + IconHaloWidth, + IconOpacity, + IconTranslate, + IconTranslateAnchor, + TextColor, + TextHaloBlur, + TextHaloColor, + TextHaloWidth, + TextOpacity, + TextTranslate, + TextTranslateAnchor, + IconColorTransition, + IconHaloBlurTransition, + IconHaloColorTransition, + IconHaloWidthTransition, + IconOpacityTransition, + IconTranslateTransition, + IconTranslateAnchorTransition, + TextColorTransition, + TextHaloBlurTransition, + TextHaloColorTransition, + TextHaloWidthTransition, + TextOpacityTransition, + TextTranslateTransition, + TextTranslateAnchorTransition, +}; + +MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( + {{"icon-color", mbgl::underlying_type(Property::IconColor)}, + {"icon-halo-blur", mbgl::underlying_type(Property::IconHaloBlur)}, + {"icon-halo-color", mbgl::underlying_type(Property::IconHaloColor)}, + {"icon-halo-width", mbgl::underlying_type(Property::IconHaloWidth)}, + {"icon-opacity", mbgl::underlying_type(Property::IconOpacity)}, + {"icon-translate", mbgl::underlying_type(Property::IconTranslate)}, + {"icon-translate-anchor", mbgl::underlying_type(Property::IconTranslateAnchor)}, + {"text-color", mbgl::underlying_type(Property::TextColor)}, + {"text-halo-blur", mbgl::underlying_type(Property::TextHaloBlur)}, + {"text-halo-color", mbgl::underlying_type(Property::TextHaloColor)}, + {"text-halo-width", mbgl::underlying_type(Property::TextHaloWidth)}, + {"text-opacity", mbgl::underlying_type(Property::TextOpacity)}, + {"text-translate", mbgl::underlying_type(Property::TextTranslate)}, + {"text-translate-anchor", mbgl::underlying_type(Property::TextTranslateAnchor)}, + {"icon-color-transition", mbgl::underlying_type(Property::IconColorTransition)}, + {"icon-halo-blur-transition", mbgl::underlying_type(Property::IconHaloBlurTransition)}, + {"icon-halo-color-transition", mbgl::underlying_type(Property::IconHaloColorTransition)}, + {"icon-halo-width-transition", mbgl::underlying_type(Property::IconHaloWidthTransition)}, + {"icon-opacity-transition", mbgl::underlying_type(Property::IconOpacityTransition)}, + {"icon-translate-transition", mbgl::underlying_type(Property::IconTranslateTransition)}, + {"icon-translate-anchor-transition", mbgl::underlying_type(Property::IconTranslateAnchorTransition)}, + {"text-color-transition", mbgl::underlying_type(Property::TextColorTransition)}, + {"text-halo-blur-transition", mbgl::underlying_type(Property::TextHaloBlurTransition)}, + {"text-halo-color-transition", mbgl::underlying_type(Property::TextHaloColorTransition)}, + {"text-halo-width-transition", mbgl::underlying_type(Property::TextHaloWidthTransition)}, + {"text-opacity-transition", mbgl::underlying_type(Property::TextOpacityTransition)}, + {"text-translate-transition", mbgl::underlying_type(Property::TextTranslateTransition)}, + {"text-translate-anchor-transition", mbgl::underlying_type(Property::TextTranslateAnchorTransition)}}); + +} // namespace - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "icon-color", mbgl::underlying_type(Property::IconColor) }, - { "icon-halo-blur", mbgl::underlying_type(Property::IconHaloBlur) }, - { "icon-halo-color", mbgl::underlying_type(Property::IconHaloColor) }, - { "icon-halo-width", mbgl::underlying_type(Property::IconHaloWidth) }, - { "icon-opacity", mbgl::underlying_type(Property::IconOpacity) }, - { "icon-translate", mbgl::underlying_type(Property::IconTranslate) }, - { "icon-translate-anchor", mbgl::underlying_type(Property::IconTranslateAnchor) }, - { "text-color", mbgl::underlying_type(Property::TextColor) }, - { "text-halo-blur", mbgl::underlying_type(Property::TextHaloBlur) }, - { "text-halo-color", mbgl::underlying_type(Property::TextHaloColor) }, - { "text-halo-width", mbgl::underlying_type(Property::TextHaloWidth) }, - { "text-opacity", mbgl::underlying_type(Property::TextOpacity) }, - { "text-translate", mbgl::underlying_type(Property::TextTranslate) }, - { "text-translate-anchor", mbgl::underlying_type(Property::TextTranslateAnchor) }, - { "icon-color-transition", mbgl::underlying_type(Property::IconColorTransition) }, - { "icon-halo-blur-transition", mbgl::underlying_type(Property::IconHaloBlurTransition) }, - { "icon-halo-color-transition", mbgl::underlying_type(Property::IconHaloColorTransition) }, - { "icon-halo-width-transition", mbgl::underlying_type(Property::IconHaloWidthTransition) }, - { "icon-opacity-transition", mbgl::underlying_type(Property::IconOpacityTransition) }, - { "icon-translate-transition", mbgl::underlying_type(Property::IconTranslateTransition) }, - { "icon-translate-anchor-transition", mbgl::underlying_type(Property::IconTranslateAnchorTransition) }, - { "text-color-transition", mbgl::underlying_type(Property::TextColorTransition) }, - { "text-halo-blur-transition", mbgl::underlying_type(Property::TextHaloBlurTransition) }, - { "text-halo-color-transition", mbgl::underlying_type(Property::TextHaloColorTransition) }, - { "text-halo-width-transition", mbgl::underlying_type(Property::TextHaloWidthTransition) }, - { "text-opacity-transition", mbgl::underlying_type(Property::TextOpacityTransition) }, - { "text-translate-transition", mbgl::underlying_type(Property::TextTranslateTransition) }, - { "text-translate-anchor-transition", mbgl::underlying_type(Property::TextTranslateAnchorTransition) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { +optional SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { return Error { "layer doesn't support this property" }; } @@ -1360,6 +1363,73 @@ optional SymbolLayer::setPaintProperty(const std::string& name, const Con return Error { "layer doesn't support this property" }; } +LayerProperty SymbolLayer::getPaintProperty(const std::string& name) const { + const auto it = paintProperties.find(name.c_str()); + if (it == paintProperties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::IconColor: + return conversion::makeLayerProperty(getIconColor()); + case Property::IconHaloBlur: + return conversion::makeLayerProperty(getIconHaloBlur()); + case Property::IconHaloColor: + return conversion::makeLayerProperty(getIconHaloColor()); + case Property::IconHaloWidth: + return conversion::makeLayerProperty(getIconHaloWidth()); + case Property::IconOpacity: + return conversion::makeLayerProperty(getIconOpacity()); + case Property::IconTranslate: + return conversion::makeLayerProperty(getIconTranslate()); + case Property::IconTranslateAnchor: + return conversion::makeLayerProperty(getIconTranslateAnchor()); + case Property::TextColor: + return conversion::makeLayerProperty(getTextColor()); + case Property::TextHaloBlur: + return conversion::makeLayerProperty(getTextHaloBlur()); + case Property::TextHaloColor: + return conversion::makeLayerProperty(getTextHaloColor()); + case Property::TextHaloWidth: + return conversion::makeLayerProperty(getTextHaloWidth()); + case Property::TextOpacity: + return conversion::makeLayerProperty(getTextOpacity()); + case Property::TextTranslate: + return conversion::makeLayerProperty(getTextTranslate()); + case Property::TextTranslateAnchor: + return conversion::makeLayerProperty(getTextTranslateAnchor()); + case Property::IconColorTransition: + return conversion::makeLayerProperty(getIconColorTransition()); + case Property::IconHaloBlurTransition: + return conversion::makeLayerProperty(getIconHaloBlurTransition()); + case Property::IconHaloColorTransition: + return conversion::makeLayerProperty(getIconHaloColorTransition()); + case Property::IconHaloWidthTransition: + return conversion::makeLayerProperty(getIconHaloWidthTransition()); + case Property::IconOpacityTransition: + return conversion::makeLayerProperty(getIconOpacityTransition()); + case Property::IconTranslateTransition: + return conversion::makeLayerProperty(getIconTranslateTransition()); + case Property::IconTranslateAnchorTransition: + return conversion::makeLayerProperty(getIconTranslateAnchorTransition()); + case Property::TextColorTransition: + return conversion::makeLayerProperty(getTextColorTransition()); + case Property::TextHaloBlurTransition: + return conversion::makeLayerProperty(getTextHaloBlurTransition()); + case Property::TextHaloColorTransition: + return conversion::makeLayerProperty(getTextHaloColorTransition()); + case Property::TextHaloWidthTransition: + return conversion::makeLayerProperty(getTextHaloWidthTransition()); + case Property::TextOpacityTransition: + return conversion::makeLayerProperty(getTextOpacityTransition()); + case Property::TextTranslateTransition: + return conversion::makeLayerProperty(getTextTranslateTransition()); + case Property::TextTranslateAnchorTransition: + return conversion::makeLayerProperty(getTextTranslateAnchorTransition()); + } + return {}; +} + optional SymbolLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { return Layer::setVisibility(value); diff --git a/src/mbgl/util/color.cpp b/src/mbgl/util/color.cpp index 8a880e8760..44f815e8b8 100644 --- a/src/mbgl/util/color.cpp +++ b/src/mbgl/util/color.cpp @@ -45,10 +45,7 @@ std::array Color::toArray() const { } mbgl::Value Color::toObject() const { - return mapbox::base::ValueObject{{"r", double(r)}, - {"g", double(g)}, - {"b", double(b)}, - {"a", double(a)}}; + return mapbox::base::ValueObject{{"r", double(r)}, {"g", double(g)}, {"b", double(b)}, {"a", double(a)}}; } } // namespace mbgl -- cgit v1.2.1 From 1d6660b5521b9f67afad8bcfe6a6b649c8b3c317 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 25 Sep 2019 00:01:59 +0300 Subject: [core] Fix clang format errors --- src/mbgl/style/layers/background_layer.cpp | 40 ++++--- src/mbgl/style/layers/circle_layer.cpp | 120 ++++++++++---------- src/mbgl/style/layers/fill_extrusion_layer.cpp | 90 ++++++++------- src/mbgl/style/layers/fill_layer.cpp | 80 ++++++------- src/mbgl/style/layers/heatmap_layer.cpp | 60 +++++----- src/mbgl/style/layers/hillshade_layer.cpp | 70 ++++++------ src/mbgl/style/layers/layer.cpp.ejs | 22 ++-- src/mbgl/style/layers/line_layer.cpp | 120 ++++++++++---------- src/mbgl/style/layers/raster_layer.cpp | 90 ++++++++------- src/mbgl/style/layers/symbol_layer.cpp | 150 +++++++++++++------------ 10 files changed, 441 insertions(+), 401 deletions(-) diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 4c37022e70..735d653e85 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -159,20 +159,25 @@ enum class Property { BackgroundPatternTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"background-color", mbgl::underlying_type(Property::BackgroundColor)}, - {"background-opacity", mbgl::underlying_type(Property::BackgroundOpacity)}, - {"background-pattern", mbgl::underlying_type(Property::BackgroundPattern)}, - {"background-color-transition", mbgl::underlying_type(Property::BackgroundColorTransition)}, - {"background-opacity-transition", mbgl::underlying_type(Property::BackgroundOpacityTransition)}, - {"background-pattern-transition", mbgl::underlying_type(Property::BackgroundPatternTransition)}}); + {{"background-color", toUint8(Property::BackgroundColor)}, + {"background-opacity", toUint8(Property::BackgroundOpacity)}, + {"background-pattern", toUint8(Property::BackgroundPattern)}, + {"background-color-transition", toUint8(Property::BackgroundColorTransition)}, + {"background-opacity-transition", toUint8(Property::BackgroundOpacityTransition)}, + {"background-pattern-transition", toUint8(Property::BackgroundPatternTransition)}}); } // namespace optional BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -220,24 +225,23 @@ optional BackgroundLayer::setPaintProperty(const std::string& name, const if (!transition) { return error; } - + if (property == Property::BackgroundColorTransition) { setBackgroundColorTransition(*transition); return nullopt; } - + if (property == Property::BackgroundOpacityTransition) { setBackgroundOpacityTransition(*transition); return nullopt; } - + if (property == Property::BackgroundPatternTransition) { setBackgroundPatternTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty BackgroundLayer::getPaintProperty(const std::string& name) const { @@ -248,17 +252,17 @@ LayerProperty BackgroundLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::BackgroundColor: - return conversion::makeLayerProperty(getBackgroundColor()); + return makeLayerProperty(getBackgroundColor()); case Property::BackgroundOpacity: - return conversion::makeLayerProperty(getBackgroundOpacity()); + return makeLayerProperty(getBackgroundOpacity()); case Property::BackgroundPattern: - return conversion::makeLayerProperty(getBackgroundPattern()); + return makeLayerProperty(getBackgroundPattern()); case Property::BackgroundColorTransition: - return conversion::makeLayerProperty(getBackgroundColorTransition()); + return makeLayerProperty(getBackgroundColorTransition()); case Property::BackgroundOpacityTransition: - return conversion::makeLayerProperty(getBackgroundOpacityTransition()); + return makeLayerProperty(getBackgroundOpacityTransition()); case Property::BackgroundPatternTransition: - return conversion::makeLayerProperty(getBackgroundPatternTransition()); + return makeLayerProperty(getBackgroundPatternTransition()); } return {}; } diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 3fec7fd677..73171713b8 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -391,36 +391,41 @@ enum class Property { CircleTranslateAnchorTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"circle-blur", mbgl::underlying_type(Property::CircleBlur)}, - {"circle-color", mbgl::underlying_type(Property::CircleColor)}, - {"circle-opacity", mbgl::underlying_type(Property::CircleOpacity)}, - {"circle-pitch-alignment", mbgl::underlying_type(Property::CirclePitchAlignment)}, - {"circle-pitch-scale", mbgl::underlying_type(Property::CirclePitchScale)}, - {"circle-radius", mbgl::underlying_type(Property::CircleRadius)}, - {"circle-stroke-color", mbgl::underlying_type(Property::CircleStrokeColor)}, - {"circle-stroke-opacity", mbgl::underlying_type(Property::CircleStrokeOpacity)}, - {"circle-stroke-width", mbgl::underlying_type(Property::CircleStrokeWidth)}, - {"circle-translate", mbgl::underlying_type(Property::CircleTranslate)}, - {"circle-translate-anchor", mbgl::underlying_type(Property::CircleTranslateAnchor)}, - {"circle-blur-transition", mbgl::underlying_type(Property::CircleBlurTransition)}, - {"circle-color-transition", mbgl::underlying_type(Property::CircleColorTransition)}, - {"circle-opacity-transition", mbgl::underlying_type(Property::CircleOpacityTransition)}, - {"circle-pitch-alignment-transition", mbgl::underlying_type(Property::CirclePitchAlignmentTransition)}, - {"circle-pitch-scale-transition", mbgl::underlying_type(Property::CirclePitchScaleTransition)}, - {"circle-radius-transition", mbgl::underlying_type(Property::CircleRadiusTransition)}, - {"circle-stroke-color-transition", mbgl::underlying_type(Property::CircleStrokeColorTransition)}, - {"circle-stroke-opacity-transition", mbgl::underlying_type(Property::CircleStrokeOpacityTransition)}, - {"circle-stroke-width-transition", mbgl::underlying_type(Property::CircleStrokeWidthTransition)}, - {"circle-translate-transition", mbgl::underlying_type(Property::CircleTranslateTransition)}, - {"circle-translate-anchor-transition", mbgl::underlying_type(Property::CircleTranslateAnchorTransition)}}); + {{"circle-blur", toUint8(Property::CircleBlur)}, + {"circle-color", toUint8(Property::CircleColor)}, + {"circle-opacity", toUint8(Property::CircleOpacity)}, + {"circle-pitch-alignment", toUint8(Property::CirclePitchAlignment)}, + {"circle-pitch-scale", toUint8(Property::CirclePitchScale)}, + {"circle-radius", toUint8(Property::CircleRadius)}, + {"circle-stroke-color", toUint8(Property::CircleStrokeColor)}, + {"circle-stroke-opacity", toUint8(Property::CircleStrokeOpacity)}, + {"circle-stroke-width", toUint8(Property::CircleStrokeWidth)}, + {"circle-translate", toUint8(Property::CircleTranslate)}, + {"circle-translate-anchor", toUint8(Property::CircleTranslateAnchor)}, + {"circle-blur-transition", toUint8(Property::CircleBlurTransition)}, + {"circle-color-transition", toUint8(Property::CircleColorTransition)}, + {"circle-opacity-transition", toUint8(Property::CircleOpacityTransition)}, + {"circle-pitch-alignment-transition", toUint8(Property::CirclePitchAlignmentTransition)}, + {"circle-pitch-scale-transition", toUint8(Property::CirclePitchScaleTransition)}, + {"circle-radius-transition", toUint8(Property::CircleRadiusTransition)}, + {"circle-stroke-color-transition", toUint8(Property::CircleStrokeColorTransition)}, + {"circle-stroke-opacity-transition", toUint8(Property::CircleStrokeOpacityTransition)}, + {"circle-stroke-width-transition", toUint8(Property::CircleStrokeWidthTransition)}, + {"circle-translate-transition", toUint8(Property::CircleTranslateTransition)}, + {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)}}); } // namespace optional CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -533,64 +538,63 @@ optional CircleLayer::setPaintProperty(const std::string& name, const Con if (!transition) { return error; } - + if (property == Property::CircleBlurTransition) { setCircleBlurTransition(*transition); return nullopt; } - + if (property == Property::CircleColorTransition) { setCircleColorTransition(*transition); return nullopt; } - + if (property == Property::CircleOpacityTransition) { setCircleOpacityTransition(*transition); return nullopt; } - + if (property == Property::CirclePitchAlignmentTransition) { setCirclePitchAlignmentTransition(*transition); return nullopt; } - + if (property == Property::CirclePitchScaleTransition) { setCirclePitchScaleTransition(*transition); return nullopt; } - + if (property == Property::CircleRadiusTransition) { setCircleRadiusTransition(*transition); return nullopt; } - + if (property == Property::CircleStrokeColorTransition) { setCircleStrokeColorTransition(*transition); return nullopt; } - + if (property == Property::CircleStrokeOpacityTransition) { setCircleStrokeOpacityTransition(*transition); return nullopt; } - + if (property == Property::CircleStrokeWidthTransition) { setCircleStrokeWidthTransition(*transition); return nullopt; } - + if (property == Property::CircleTranslateTransition) { setCircleTranslateTransition(*transition); return nullopt; } - + if (property == Property::CircleTranslateAnchorTransition) { setCircleTranslateAnchorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty CircleLayer::getPaintProperty(const std::string& name) const { @@ -601,49 +605,49 @@ LayerProperty CircleLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::CircleBlur: - return conversion::makeLayerProperty(getCircleBlur()); + return makeLayerProperty(getCircleBlur()); case Property::CircleColor: - return conversion::makeLayerProperty(getCircleColor()); + return makeLayerProperty(getCircleColor()); case Property::CircleOpacity: - return conversion::makeLayerProperty(getCircleOpacity()); + return makeLayerProperty(getCircleOpacity()); case Property::CirclePitchAlignment: - return conversion::makeLayerProperty(getCirclePitchAlignment()); + return makeLayerProperty(getCirclePitchAlignment()); case Property::CirclePitchScale: - return conversion::makeLayerProperty(getCirclePitchScale()); + return makeLayerProperty(getCirclePitchScale()); case Property::CircleRadius: - return conversion::makeLayerProperty(getCircleRadius()); + return makeLayerProperty(getCircleRadius()); case Property::CircleStrokeColor: - return conversion::makeLayerProperty(getCircleStrokeColor()); + return makeLayerProperty(getCircleStrokeColor()); case Property::CircleStrokeOpacity: - return conversion::makeLayerProperty(getCircleStrokeOpacity()); + return makeLayerProperty(getCircleStrokeOpacity()); case Property::CircleStrokeWidth: - return conversion::makeLayerProperty(getCircleStrokeWidth()); + return makeLayerProperty(getCircleStrokeWidth()); case Property::CircleTranslate: - return conversion::makeLayerProperty(getCircleTranslate()); + return makeLayerProperty(getCircleTranslate()); case Property::CircleTranslateAnchor: - return conversion::makeLayerProperty(getCircleTranslateAnchor()); + return makeLayerProperty(getCircleTranslateAnchor()); case Property::CircleBlurTransition: - return conversion::makeLayerProperty(getCircleBlurTransition()); + return makeLayerProperty(getCircleBlurTransition()); case Property::CircleColorTransition: - return conversion::makeLayerProperty(getCircleColorTransition()); + return makeLayerProperty(getCircleColorTransition()); case Property::CircleOpacityTransition: - return conversion::makeLayerProperty(getCircleOpacityTransition()); + return makeLayerProperty(getCircleOpacityTransition()); case Property::CirclePitchAlignmentTransition: - return conversion::makeLayerProperty(getCirclePitchAlignmentTransition()); + return makeLayerProperty(getCirclePitchAlignmentTransition()); case Property::CirclePitchScaleTransition: - return conversion::makeLayerProperty(getCirclePitchScaleTransition()); + return makeLayerProperty(getCirclePitchScaleTransition()); case Property::CircleRadiusTransition: - return conversion::makeLayerProperty(getCircleRadiusTransition()); + return makeLayerProperty(getCircleRadiusTransition()); case Property::CircleStrokeColorTransition: - return conversion::makeLayerProperty(getCircleStrokeColorTransition()); + return makeLayerProperty(getCircleStrokeColorTransition()); case Property::CircleStrokeOpacityTransition: - return conversion::makeLayerProperty(getCircleStrokeOpacityTransition()); + return makeLayerProperty(getCircleStrokeOpacityTransition()); case Property::CircleStrokeWidthTransition: - return conversion::makeLayerProperty(getCircleStrokeWidthTransition()); + return makeLayerProperty(getCircleStrokeWidthTransition()); case Property::CircleTranslateTransition: - return conversion::makeLayerProperty(getCircleTranslateTransition()); + return makeLayerProperty(getCircleTranslateTransition()); case Property::CircleTranslateAnchorTransition: - return conversion::makeLayerProperty(getCircleTranslateAnchorTransition()); + return makeLayerProperty(getCircleTranslateAnchorTransition()); } return {}; } diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 43183255a1..04206e670d 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -304,30 +304,35 @@ enum class Property { FillExtrusionVerticalGradientTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"fill-extrusion-base", mbgl::underlying_type(Property::FillExtrusionBase)}, - {"fill-extrusion-color", mbgl::underlying_type(Property::FillExtrusionColor)}, - {"fill-extrusion-height", mbgl::underlying_type(Property::FillExtrusionHeight)}, - {"fill-extrusion-opacity", mbgl::underlying_type(Property::FillExtrusionOpacity)}, - {"fill-extrusion-pattern", mbgl::underlying_type(Property::FillExtrusionPattern)}, - {"fill-extrusion-translate", mbgl::underlying_type(Property::FillExtrusionTranslate)}, - {"fill-extrusion-translate-anchor", mbgl::underlying_type(Property::FillExtrusionTranslateAnchor)}, - {"fill-extrusion-vertical-gradient", mbgl::underlying_type(Property::FillExtrusionVerticalGradient)}, - {"fill-extrusion-base-transition", mbgl::underlying_type(Property::FillExtrusionBaseTransition)}, - {"fill-extrusion-color-transition", mbgl::underlying_type(Property::FillExtrusionColorTransition)}, - {"fill-extrusion-height-transition", mbgl::underlying_type(Property::FillExtrusionHeightTransition)}, - {"fill-extrusion-opacity-transition", mbgl::underlying_type(Property::FillExtrusionOpacityTransition)}, - {"fill-extrusion-pattern-transition", mbgl::underlying_type(Property::FillExtrusionPatternTransition)}, - {"fill-extrusion-translate-transition", mbgl::underlying_type(Property::FillExtrusionTranslateTransition)}, - {"fill-extrusion-translate-anchor-transition", mbgl::underlying_type(Property::FillExtrusionTranslateAnchorTransition)}, - {"fill-extrusion-vertical-gradient-transition", mbgl::underlying_type(Property::FillExtrusionVerticalGradientTransition)}}); + {{"fill-extrusion-base", toUint8(Property::FillExtrusionBase)}, + {"fill-extrusion-color", toUint8(Property::FillExtrusionColor)}, + {"fill-extrusion-height", toUint8(Property::FillExtrusionHeight)}, + {"fill-extrusion-opacity", toUint8(Property::FillExtrusionOpacity)}, + {"fill-extrusion-pattern", toUint8(Property::FillExtrusionPattern)}, + {"fill-extrusion-translate", toUint8(Property::FillExtrusionTranslate)}, + {"fill-extrusion-translate-anchor", toUint8(Property::FillExtrusionTranslateAnchor)}, + {"fill-extrusion-vertical-gradient", toUint8(Property::FillExtrusionVerticalGradient)}, + {"fill-extrusion-base-transition", toUint8(Property::FillExtrusionBaseTransition)}, + {"fill-extrusion-color-transition", toUint8(Property::FillExtrusionColorTransition)}, + {"fill-extrusion-height-transition", toUint8(Property::FillExtrusionHeightTransition)}, + {"fill-extrusion-opacity-transition", toUint8(Property::FillExtrusionOpacityTransition)}, + {"fill-extrusion-pattern-transition", toUint8(Property::FillExtrusionPatternTransition)}, + {"fill-extrusion-translate-transition", toUint8(Property::FillExtrusionTranslateTransition)}, + {"fill-extrusion-translate-anchor-transition", toUint8(Property::FillExtrusionTranslateAnchorTransition)}, + {"fill-extrusion-vertical-gradient-transition", toUint8(Property::FillExtrusionVerticalGradientTransition)}}); } // namespace optional FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -430,49 +435,48 @@ optional FillExtrusionLayer::setPaintProperty(const std::string& name, co if (!transition) { return error; } - + if (property == Property::FillExtrusionBaseTransition) { setFillExtrusionBaseTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionColorTransition) { setFillExtrusionColorTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionHeightTransition) { setFillExtrusionHeightTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionOpacityTransition) { setFillExtrusionOpacityTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionPatternTransition) { setFillExtrusionPatternTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionTranslateTransition) { setFillExtrusionTranslateTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionTranslateAnchorTransition) { setFillExtrusionTranslateAnchorTransition(*transition); return nullopt; } - + if (property == Property::FillExtrusionVerticalGradientTransition) { setFillExtrusionVerticalGradientTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty FillExtrusionLayer::getPaintProperty(const std::string& name) const { @@ -483,37 +487,37 @@ LayerProperty FillExtrusionLayer::getPaintProperty(const std::string& name) cons switch (static_cast(it->second)) { case Property::FillExtrusionBase: - return conversion::makeLayerProperty(getFillExtrusionBase()); + return makeLayerProperty(getFillExtrusionBase()); case Property::FillExtrusionColor: - return conversion::makeLayerProperty(getFillExtrusionColor()); + return makeLayerProperty(getFillExtrusionColor()); case Property::FillExtrusionHeight: - return conversion::makeLayerProperty(getFillExtrusionHeight()); + return makeLayerProperty(getFillExtrusionHeight()); case Property::FillExtrusionOpacity: - return conversion::makeLayerProperty(getFillExtrusionOpacity()); + return makeLayerProperty(getFillExtrusionOpacity()); case Property::FillExtrusionPattern: - return conversion::makeLayerProperty(getFillExtrusionPattern()); + return makeLayerProperty(getFillExtrusionPattern()); case Property::FillExtrusionTranslate: - return conversion::makeLayerProperty(getFillExtrusionTranslate()); + return makeLayerProperty(getFillExtrusionTranslate()); case Property::FillExtrusionTranslateAnchor: - return conversion::makeLayerProperty(getFillExtrusionTranslateAnchor()); + return makeLayerProperty(getFillExtrusionTranslateAnchor()); case Property::FillExtrusionVerticalGradient: - return conversion::makeLayerProperty(getFillExtrusionVerticalGradient()); + return makeLayerProperty(getFillExtrusionVerticalGradient()); case Property::FillExtrusionBaseTransition: - return conversion::makeLayerProperty(getFillExtrusionBaseTransition()); + return makeLayerProperty(getFillExtrusionBaseTransition()); case Property::FillExtrusionColorTransition: - return conversion::makeLayerProperty(getFillExtrusionColorTransition()); + return makeLayerProperty(getFillExtrusionColorTransition()); case Property::FillExtrusionHeightTransition: - return conversion::makeLayerProperty(getFillExtrusionHeightTransition()); + return makeLayerProperty(getFillExtrusionHeightTransition()); case Property::FillExtrusionOpacityTransition: - return conversion::makeLayerProperty(getFillExtrusionOpacityTransition()); + return makeLayerProperty(getFillExtrusionOpacityTransition()); case Property::FillExtrusionPatternTransition: - return conversion::makeLayerProperty(getFillExtrusionPatternTransition()); + return makeLayerProperty(getFillExtrusionPatternTransition()); case Property::FillExtrusionTranslateTransition: - return conversion::makeLayerProperty(getFillExtrusionTranslateTransition()); + return makeLayerProperty(getFillExtrusionTranslateTransition()); case Property::FillExtrusionTranslateAnchorTransition: - return conversion::makeLayerProperty(getFillExtrusionTranslateAnchorTransition()); + return makeLayerProperty(getFillExtrusionTranslateAnchorTransition()); case Property::FillExtrusionVerticalGradientTransition: - return conversion::makeLayerProperty(getFillExtrusionVerticalGradientTransition()); + return makeLayerProperty(getFillExtrusionVerticalGradientTransition()); } return {}; } diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 9afc99d1d3..25bf97bb6d 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -275,28 +275,33 @@ enum class Property { FillTranslateAnchorTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"fill-antialias", mbgl::underlying_type(Property::FillAntialias)}, - {"fill-color", mbgl::underlying_type(Property::FillColor)}, - {"fill-opacity", mbgl::underlying_type(Property::FillOpacity)}, - {"fill-outline-color", mbgl::underlying_type(Property::FillOutlineColor)}, - {"fill-pattern", mbgl::underlying_type(Property::FillPattern)}, - {"fill-translate", mbgl::underlying_type(Property::FillTranslate)}, - {"fill-translate-anchor", mbgl::underlying_type(Property::FillTranslateAnchor)}, - {"fill-antialias-transition", mbgl::underlying_type(Property::FillAntialiasTransition)}, - {"fill-color-transition", mbgl::underlying_type(Property::FillColorTransition)}, - {"fill-opacity-transition", mbgl::underlying_type(Property::FillOpacityTransition)}, - {"fill-outline-color-transition", mbgl::underlying_type(Property::FillOutlineColorTransition)}, - {"fill-pattern-transition", mbgl::underlying_type(Property::FillPatternTransition)}, - {"fill-translate-transition", mbgl::underlying_type(Property::FillTranslateTransition)}, - {"fill-translate-anchor-transition", mbgl::underlying_type(Property::FillTranslateAnchorTransition)}}); + {{"fill-antialias", toUint8(Property::FillAntialias)}, + {"fill-color", toUint8(Property::FillColor)}, + {"fill-opacity", toUint8(Property::FillOpacity)}, + {"fill-outline-color", toUint8(Property::FillOutlineColor)}, + {"fill-pattern", toUint8(Property::FillPattern)}, + {"fill-translate", toUint8(Property::FillTranslate)}, + {"fill-translate-anchor", toUint8(Property::FillTranslateAnchor)}, + {"fill-antialias-transition", toUint8(Property::FillAntialiasTransition)}, + {"fill-color-transition", toUint8(Property::FillColorTransition)}, + {"fill-opacity-transition", toUint8(Property::FillOpacityTransition)}, + {"fill-outline-color-transition", toUint8(Property::FillOutlineColorTransition)}, + {"fill-pattern-transition", toUint8(Property::FillPatternTransition)}, + {"fill-translate-transition", toUint8(Property::FillTranslateTransition)}, + {"fill-translate-anchor-transition", toUint8(Property::FillTranslateAnchorTransition)}}); } // namespace optional FillLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -387,44 +392,43 @@ optional FillLayer::setPaintProperty(const std::string& name, const Conve if (!transition) { return error; } - + if (property == Property::FillAntialiasTransition) { setFillAntialiasTransition(*transition); return nullopt; } - + if (property == Property::FillColorTransition) { setFillColorTransition(*transition); return nullopt; } - + if (property == Property::FillOpacityTransition) { setFillOpacityTransition(*transition); return nullopt; } - + if (property == Property::FillOutlineColorTransition) { setFillOutlineColorTransition(*transition); return nullopt; } - + if (property == Property::FillPatternTransition) { setFillPatternTransition(*transition); return nullopt; } - + if (property == Property::FillTranslateTransition) { setFillTranslateTransition(*transition); return nullopt; } - + if (property == Property::FillTranslateAnchorTransition) { setFillTranslateAnchorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty FillLayer::getPaintProperty(const std::string& name) const { @@ -435,33 +439,33 @@ LayerProperty FillLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::FillAntialias: - return conversion::makeLayerProperty(getFillAntialias()); + return makeLayerProperty(getFillAntialias()); case Property::FillColor: - return conversion::makeLayerProperty(getFillColor()); + return makeLayerProperty(getFillColor()); case Property::FillOpacity: - return conversion::makeLayerProperty(getFillOpacity()); + return makeLayerProperty(getFillOpacity()); case Property::FillOutlineColor: - return conversion::makeLayerProperty(getFillOutlineColor()); + return makeLayerProperty(getFillOutlineColor()); case Property::FillPattern: - return conversion::makeLayerProperty(getFillPattern()); + return makeLayerProperty(getFillPattern()); case Property::FillTranslate: - return conversion::makeLayerProperty(getFillTranslate()); + return makeLayerProperty(getFillTranslate()); case Property::FillTranslateAnchor: - return conversion::makeLayerProperty(getFillTranslateAnchor()); + return makeLayerProperty(getFillTranslateAnchor()); case Property::FillAntialiasTransition: - return conversion::makeLayerProperty(getFillAntialiasTransition()); + return makeLayerProperty(getFillAntialiasTransition()); case Property::FillColorTransition: - return conversion::makeLayerProperty(getFillColorTransition()); + return makeLayerProperty(getFillColorTransition()); case Property::FillOpacityTransition: - return conversion::makeLayerProperty(getFillOpacityTransition()); + return makeLayerProperty(getFillOpacityTransition()); case Property::FillOutlineColorTransition: - return conversion::makeLayerProperty(getFillOutlineColorTransition()); + return makeLayerProperty(getFillOutlineColorTransition()); case Property::FillPatternTransition: - return conversion::makeLayerProperty(getFillPatternTransition()); + return makeLayerProperty(getFillPatternTransition()); case Property::FillTranslateTransition: - return conversion::makeLayerProperty(getFillTranslateTransition()); + return makeLayerProperty(getFillTranslateTransition()); case Property::FillTranslateAnchorTransition: - return conversion::makeLayerProperty(getFillTranslateAnchorTransition()); + return makeLayerProperty(getFillTranslateAnchorTransition()); } return {}; } diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 417e828a1d..3db78c4cf5 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -219,24 +219,29 @@ enum class Property { HeatmapWeightTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"heatmap-color", mbgl::underlying_type(Property::HeatmapColor)}, - {"heatmap-intensity", mbgl::underlying_type(Property::HeatmapIntensity)}, - {"heatmap-opacity", mbgl::underlying_type(Property::HeatmapOpacity)}, - {"heatmap-radius", mbgl::underlying_type(Property::HeatmapRadius)}, - {"heatmap-weight", mbgl::underlying_type(Property::HeatmapWeight)}, - {"heatmap-color-transition", mbgl::underlying_type(Property::HeatmapColorTransition)}, - {"heatmap-intensity-transition", mbgl::underlying_type(Property::HeatmapIntensityTransition)}, - {"heatmap-opacity-transition", mbgl::underlying_type(Property::HeatmapOpacityTransition)}, - {"heatmap-radius-transition", mbgl::underlying_type(Property::HeatmapRadiusTransition)}, - {"heatmap-weight-transition", mbgl::underlying_type(Property::HeatmapWeightTransition)}}); + {{"heatmap-color", toUint8(Property::HeatmapColor)}, + {"heatmap-intensity", toUint8(Property::HeatmapIntensity)}, + {"heatmap-opacity", toUint8(Property::HeatmapOpacity)}, + {"heatmap-radius", toUint8(Property::HeatmapRadius)}, + {"heatmap-weight", toUint8(Property::HeatmapWeight)}, + {"heatmap-color-transition", toUint8(Property::HeatmapColorTransition)}, + {"heatmap-intensity-transition", toUint8(Property::HeatmapIntensityTransition)}, + {"heatmap-opacity-transition", toUint8(Property::HeatmapOpacityTransition)}, + {"heatmap-radius-transition", toUint8(Property::HeatmapRadiusTransition)}, + {"heatmap-weight-transition", toUint8(Property::HeatmapWeightTransition)}}); } // namespace optional HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -298,34 +303,33 @@ optional HeatmapLayer::setPaintProperty(const std::string& name, const Co if (!transition) { return error; } - + if (property == Property::HeatmapColorTransition) { setHeatmapColorTransition(*transition); return nullopt; } - + if (property == Property::HeatmapIntensityTransition) { setHeatmapIntensityTransition(*transition); return nullopt; } - + if (property == Property::HeatmapOpacityTransition) { setHeatmapOpacityTransition(*transition); return nullopt; } - + if (property == Property::HeatmapRadiusTransition) { setHeatmapRadiusTransition(*transition); return nullopt; } - + if (property == Property::HeatmapWeightTransition) { setHeatmapWeightTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty HeatmapLayer::getPaintProperty(const std::string& name) const { @@ -336,25 +340,25 @@ LayerProperty HeatmapLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::HeatmapColor: - return conversion::makeLayerProperty(getHeatmapColor()); + return makeLayerProperty(getHeatmapColor()); case Property::HeatmapIntensity: - return conversion::makeLayerProperty(getHeatmapIntensity()); + return makeLayerProperty(getHeatmapIntensity()); case Property::HeatmapOpacity: - return conversion::makeLayerProperty(getHeatmapOpacity()); + return makeLayerProperty(getHeatmapOpacity()); case Property::HeatmapRadius: - return conversion::makeLayerProperty(getHeatmapRadius()); + return makeLayerProperty(getHeatmapRadius()); case Property::HeatmapWeight: - return conversion::makeLayerProperty(getHeatmapWeight()); + return makeLayerProperty(getHeatmapWeight()); case Property::HeatmapColorTransition: - return conversion::makeLayerProperty(getHeatmapColorTransition()); + return makeLayerProperty(getHeatmapColorTransition()); case Property::HeatmapIntensityTransition: - return conversion::makeLayerProperty(getHeatmapIntensityTransition()); + return makeLayerProperty(getHeatmapIntensityTransition()); case Property::HeatmapOpacityTransition: - return conversion::makeLayerProperty(getHeatmapOpacityTransition()); + return makeLayerProperty(getHeatmapOpacityTransition()); case Property::HeatmapRadiusTransition: - return conversion::makeLayerProperty(getHeatmapRadiusTransition()); + return makeLayerProperty(getHeatmapRadiusTransition()); case Property::HeatmapWeightTransition: - return conversion::makeLayerProperty(getHeatmapWeightTransition()); + return makeLayerProperty(getHeatmapWeightTransition()); } return {}; } diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 60ef4d33f1..bda125da4a 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -246,26 +246,31 @@ enum class Property { HillshadeShadowColorTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"hillshade-accent-color", mbgl::underlying_type(Property::HillshadeAccentColor)}, - {"hillshade-exaggeration", mbgl::underlying_type(Property::HillshadeExaggeration)}, - {"hillshade-highlight-color", mbgl::underlying_type(Property::HillshadeHighlightColor)}, - {"hillshade-illumination-anchor", mbgl::underlying_type(Property::HillshadeIlluminationAnchor)}, - {"hillshade-illumination-direction", mbgl::underlying_type(Property::HillshadeIlluminationDirection)}, - {"hillshade-shadow-color", mbgl::underlying_type(Property::HillshadeShadowColor)}, - {"hillshade-accent-color-transition", mbgl::underlying_type(Property::HillshadeAccentColorTransition)}, - {"hillshade-exaggeration-transition", mbgl::underlying_type(Property::HillshadeExaggerationTransition)}, - {"hillshade-highlight-color-transition", mbgl::underlying_type(Property::HillshadeHighlightColorTransition)}, - {"hillshade-illumination-anchor-transition", mbgl::underlying_type(Property::HillshadeIlluminationAnchorTransition)}, - {"hillshade-illumination-direction-transition", mbgl::underlying_type(Property::HillshadeIlluminationDirectionTransition)}, - {"hillshade-shadow-color-transition", mbgl::underlying_type(Property::HillshadeShadowColorTransition)}}); + {{"hillshade-accent-color", toUint8(Property::HillshadeAccentColor)}, + {"hillshade-exaggeration", toUint8(Property::HillshadeExaggeration)}, + {"hillshade-highlight-color", toUint8(Property::HillshadeHighlightColor)}, + {"hillshade-illumination-anchor", toUint8(Property::HillshadeIlluminationAnchor)}, + {"hillshade-illumination-direction", toUint8(Property::HillshadeIlluminationDirection)}, + {"hillshade-shadow-color", toUint8(Property::HillshadeShadowColor)}, + {"hillshade-accent-color-transition", toUint8(Property::HillshadeAccentColorTransition)}, + {"hillshade-exaggeration-transition", toUint8(Property::HillshadeExaggerationTransition)}, + {"hillshade-highlight-color-transition", toUint8(Property::HillshadeHighlightColorTransition)}, + {"hillshade-illumination-anchor-transition", toUint8(Property::HillshadeIlluminationAnchorTransition)}, + {"hillshade-illumination-direction-transition", toUint8(Property::HillshadeIlluminationDirectionTransition)}, + {"hillshade-shadow-color-transition", toUint8(Property::HillshadeShadowColorTransition)}}); } // namespace optional HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -332,39 +337,38 @@ optional HillshadeLayer::setPaintProperty(const std::string& name, const if (!transition) { return error; } - + if (property == Property::HillshadeAccentColorTransition) { setHillshadeAccentColorTransition(*transition); return nullopt; } - + if (property == Property::HillshadeExaggerationTransition) { setHillshadeExaggerationTransition(*transition); return nullopt; } - + if (property == Property::HillshadeHighlightColorTransition) { setHillshadeHighlightColorTransition(*transition); return nullopt; } - + if (property == Property::HillshadeIlluminationAnchorTransition) { setHillshadeIlluminationAnchorTransition(*transition); return nullopt; } - + if (property == Property::HillshadeIlluminationDirectionTransition) { setHillshadeIlluminationDirectionTransition(*transition); return nullopt; } - + if (property == Property::HillshadeShadowColorTransition) { setHillshadeShadowColorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty HillshadeLayer::getPaintProperty(const std::string& name) const { @@ -375,29 +379,29 @@ LayerProperty HillshadeLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::HillshadeAccentColor: - return conversion::makeLayerProperty(getHillshadeAccentColor()); + return makeLayerProperty(getHillshadeAccentColor()); case Property::HillshadeExaggeration: - return conversion::makeLayerProperty(getHillshadeExaggeration()); + return makeLayerProperty(getHillshadeExaggeration()); case Property::HillshadeHighlightColor: - return conversion::makeLayerProperty(getHillshadeHighlightColor()); + return makeLayerProperty(getHillshadeHighlightColor()); case Property::HillshadeIlluminationAnchor: - return conversion::makeLayerProperty(getHillshadeIlluminationAnchor()); + return makeLayerProperty(getHillshadeIlluminationAnchor()); case Property::HillshadeIlluminationDirection: - return conversion::makeLayerProperty(getHillshadeIlluminationDirection()); + return makeLayerProperty(getHillshadeIlluminationDirection()); case Property::HillshadeShadowColor: - return conversion::makeLayerProperty(getHillshadeShadowColor()); + return makeLayerProperty(getHillshadeShadowColor()); case Property::HillshadeAccentColorTransition: - return conversion::makeLayerProperty(getHillshadeAccentColorTransition()); + return makeLayerProperty(getHillshadeAccentColorTransition()); case Property::HillshadeExaggerationTransition: - return conversion::makeLayerProperty(getHillshadeExaggerationTransition()); + return makeLayerProperty(getHillshadeExaggerationTransition()); case Property::HillshadeHighlightColorTransition: - return conversion::makeLayerProperty(getHillshadeHighlightColorTransition()); + return makeLayerProperty(getHillshadeHighlightColorTransition()); case Property::HillshadeIlluminationAnchorTransition: - return conversion::makeLayerProperty(getHillshadeIlluminationAnchorTransition()); + return makeLayerProperty(getHillshadeIlluminationAnchorTransition()); case Property::HillshadeIlluminationDirectionTransition: - return conversion::makeLayerProperty(getHillshadeIlluminationDirectionTransition()); + return makeLayerProperty(getHillshadeIlluminationDirectionTransition()); case Property::HillshadeShadowColorTransition: - return conversion::makeLayerProperty(getHillshadeShadowColorTransition()); + return makeLayerProperty(getHillshadeShadowColorTransition()); } return {}; } diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 04d4a81dce..81b04be267 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -201,16 +201,21 @@ enum class Property { <% } -%> }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {<%- paintProperties.map(p => `{"${p.name}", mbgl::underlying_type(Property::${camelize(p.name)})}`).join(',\n ') %>, - <%- paintProperties.map(p => `{"${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); + {<%- paintProperties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>, + <%- paintProperties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); } // namespace optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -251,14 +256,13 @@ optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& if (!transition) { return error; } - <% for (const property of paintProperties) { %> +<% for (const property of paintProperties) { %> if (property == Property::<%- camelize(property.name) %>Transition) { set<%- camelize(property.name) %>Transition(*transition); return nullopt; } - <% } %> - - return Error { "layer doesn't support this property" }; +<% } %> + return Error{"layer doesn't support this property"}; } LayerProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& name) const { @@ -270,11 +274,11 @@ LayerProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& na switch (static_cast(it->second)) { <% for (const property of paintProperties) { -%> case Property::<%- camelize(property.name) %>: - return conversion::makeLayerProperty(get<%- camelize(property.name) %>()); + return makeLayerProperty(get<%- camelize(property.name) %>()); <% } -%> <% for (const property of paintProperties) { -%> case Property::<%- camelize(property.name) %>Transition: - return conversion::makeLayerProperty(get<%- camelize(property.name) %>Transition()); + return makeLayerProperty(get<%- camelize(property.name) %>Transition()); <% } -%> } return {}; diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 491cfd48a0..ee1cfe2966 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -457,36 +457,41 @@ enum class Property { LineWidthTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"line-blur", mbgl::underlying_type(Property::LineBlur)}, - {"line-color", mbgl::underlying_type(Property::LineColor)}, - {"line-dasharray", mbgl::underlying_type(Property::LineDasharray)}, - {"line-gap-width", mbgl::underlying_type(Property::LineGapWidth)}, - {"line-gradient", mbgl::underlying_type(Property::LineGradient)}, - {"line-offset", mbgl::underlying_type(Property::LineOffset)}, - {"line-opacity", mbgl::underlying_type(Property::LineOpacity)}, - {"line-pattern", mbgl::underlying_type(Property::LinePattern)}, - {"line-translate", mbgl::underlying_type(Property::LineTranslate)}, - {"line-translate-anchor", mbgl::underlying_type(Property::LineTranslateAnchor)}, - {"line-width", mbgl::underlying_type(Property::LineWidth)}, - {"line-blur-transition", mbgl::underlying_type(Property::LineBlurTransition)}, - {"line-color-transition", mbgl::underlying_type(Property::LineColorTransition)}, - {"line-dasharray-transition", mbgl::underlying_type(Property::LineDasharrayTransition)}, - {"line-gap-width-transition", mbgl::underlying_type(Property::LineGapWidthTransition)}, - {"line-gradient-transition", mbgl::underlying_type(Property::LineGradientTransition)}, - {"line-offset-transition", mbgl::underlying_type(Property::LineOffsetTransition)}, - {"line-opacity-transition", mbgl::underlying_type(Property::LineOpacityTransition)}, - {"line-pattern-transition", mbgl::underlying_type(Property::LinePatternTransition)}, - {"line-translate-transition", mbgl::underlying_type(Property::LineTranslateTransition)}, - {"line-translate-anchor-transition", mbgl::underlying_type(Property::LineTranslateAnchorTransition)}, - {"line-width-transition", mbgl::underlying_type(Property::LineWidthTransition)}}); + {{"line-blur", toUint8(Property::LineBlur)}, + {"line-color", toUint8(Property::LineColor)}, + {"line-dasharray", toUint8(Property::LineDasharray)}, + {"line-gap-width", toUint8(Property::LineGapWidth)}, + {"line-gradient", toUint8(Property::LineGradient)}, + {"line-offset", toUint8(Property::LineOffset)}, + {"line-opacity", toUint8(Property::LineOpacity)}, + {"line-pattern", toUint8(Property::LinePattern)}, + {"line-translate", toUint8(Property::LineTranslate)}, + {"line-translate-anchor", toUint8(Property::LineTranslateAnchor)}, + {"line-width", toUint8(Property::LineWidth)}, + {"line-blur-transition", toUint8(Property::LineBlurTransition)}, + {"line-color-transition", toUint8(Property::LineColorTransition)}, + {"line-dasharray-transition", toUint8(Property::LineDasharrayTransition)}, + {"line-gap-width-transition", toUint8(Property::LineGapWidthTransition)}, + {"line-gradient-transition", toUint8(Property::LineGradientTransition)}, + {"line-offset-transition", toUint8(Property::LineOffsetTransition)}, + {"line-opacity-transition", toUint8(Property::LineOpacityTransition)}, + {"line-pattern-transition", toUint8(Property::LinePatternTransition)}, + {"line-translate-transition", toUint8(Property::LineTranslateTransition)}, + {"line-translate-anchor-transition", toUint8(Property::LineTranslateAnchorTransition)}, + {"line-width-transition", toUint8(Property::LineWidthTransition)}}); } // namespace optional LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -604,64 +609,63 @@ optional LineLayer::setPaintProperty(const std::string& name, const Conve if (!transition) { return error; } - + if (property == Property::LineBlurTransition) { setLineBlurTransition(*transition); return nullopt; } - + if (property == Property::LineColorTransition) { setLineColorTransition(*transition); return nullopt; } - + if (property == Property::LineDasharrayTransition) { setLineDasharrayTransition(*transition); return nullopt; } - + if (property == Property::LineGapWidthTransition) { setLineGapWidthTransition(*transition); return nullopt; } - + if (property == Property::LineGradientTransition) { setLineGradientTransition(*transition); return nullopt; } - + if (property == Property::LineOffsetTransition) { setLineOffsetTransition(*transition); return nullopt; } - + if (property == Property::LineOpacityTransition) { setLineOpacityTransition(*transition); return nullopt; } - + if (property == Property::LinePatternTransition) { setLinePatternTransition(*transition); return nullopt; } - + if (property == Property::LineTranslateTransition) { setLineTranslateTransition(*transition); return nullopt; } - + if (property == Property::LineTranslateAnchorTransition) { setLineTranslateAnchorTransition(*transition); return nullopt; } - + if (property == Property::LineWidthTransition) { setLineWidthTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty LineLayer::getPaintProperty(const std::string& name) const { @@ -672,49 +676,49 @@ LayerProperty LineLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::LineBlur: - return conversion::makeLayerProperty(getLineBlur()); + return makeLayerProperty(getLineBlur()); case Property::LineColor: - return conversion::makeLayerProperty(getLineColor()); + return makeLayerProperty(getLineColor()); case Property::LineDasharray: - return conversion::makeLayerProperty(getLineDasharray()); + return makeLayerProperty(getLineDasharray()); case Property::LineGapWidth: - return conversion::makeLayerProperty(getLineGapWidth()); + return makeLayerProperty(getLineGapWidth()); case Property::LineGradient: - return conversion::makeLayerProperty(getLineGradient()); + return makeLayerProperty(getLineGradient()); case Property::LineOffset: - return conversion::makeLayerProperty(getLineOffset()); + return makeLayerProperty(getLineOffset()); case Property::LineOpacity: - return conversion::makeLayerProperty(getLineOpacity()); + return makeLayerProperty(getLineOpacity()); case Property::LinePattern: - return conversion::makeLayerProperty(getLinePattern()); + return makeLayerProperty(getLinePattern()); case Property::LineTranslate: - return conversion::makeLayerProperty(getLineTranslate()); + return makeLayerProperty(getLineTranslate()); case Property::LineTranslateAnchor: - return conversion::makeLayerProperty(getLineTranslateAnchor()); + return makeLayerProperty(getLineTranslateAnchor()); case Property::LineWidth: - return conversion::makeLayerProperty(getLineWidth()); + return makeLayerProperty(getLineWidth()); case Property::LineBlurTransition: - return conversion::makeLayerProperty(getLineBlurTransition()); + return makeLayerProperty(getLineBlurTransition()); case Property::LineColorTransition: - return conversion::makeLayerProperty(getLineColorTransition()); + return makeLayerProperty(getLineColorTransition()); case Property::LineDasharrayTransition: - return conversion::makeLayerProperty(getLineDasharrayTransition()); + return makeLayerProperty(getLineDasharrayTransition()); case Property::LineGapWidthTransition: - return conversion::makeLayerProperty(getLineGapWidthTransition()); + return makeLayerProperty(getLineGapWidthTransition()); case Property::LineGradientTransition: - return conversion::makeLayerProperty(getLineGradientTransition()); + return makeLayerProperty(getLineGradientTransition()); case Property::LineOffsetTransition: - return conversion::makeLayerProperty(getLineOffsetTransition()); + return makeLayerProperty(getLineOffsetTransition()); case Property::LineOpacityTransition: - return conversion::makeLayerProperty(getLineOpacityTransition()); + return makeLayerProperty(getLineOpacityTransition()); case Property::LinePatternTransition: - return conversion::makeLayerProperty(getLinePatternTransition()); + return makeLayerProperty(getLinePatternTransition()); case Property::LineTranslateTransition: - return conversion::makeLayerProperty(getLineTranslateTransition()); + return makeLayerProperty(getLineTranslateTransition()); case Property::LineTranslateAnchorTransition: - return conversion::makeLayerProperty(getLineTranslateAnchorTransition()); + return makeLayerProperty(getLineTranslateAnchorTransition()); case Property::LineWidthTransition: - return conversion::makeLayerProperty(getLineWidthTransition()); + return makeLayerProperty(getLineWidthTransition()); } return {}; } diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index d10ba0ae8e..263cc0e2f4 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -304,30 +304,35 @@ enum class Property { RasterSaturationTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"raster-brightness-max", mbgl::underlying_type(Property::RasterBrightnessMax)}, - {"raster-brightness-min", mbgl::underlying_type(Property::RasterBrightnessMin)}, - {"raster-contrast", mbgl::underlying_type(Property::RasterContrast)}, - {"raster-fade-duration", mbgl::underlying_type(Property::RasterFadeDuration)}, - {"raster-hue-rotate", mbgl::underlying_type(Property::RasterHueRotate)}, - {"raster-opacity", mbgl::underlying_type(Property::RasterOpacity)}, - {"raster-resampling", mbgl::underlying_type(Property::RasterResampling)}, - {"raster-saturation", mbgl::underlying_type(Property::RasterSaturation)}, - {"raster-brightness-max-transition", mbgl::underlying_type(Property::RasterBrightnessMaxTransition)}, - {"raster-brightness-min-transition", mbgl::underlying_type(Property::RasterBrightnessMinTransition)}, - {"raster-contrast-transition", mbgl::underlying_type(Property::RasterContrastTransition)}, - {"raster-fade-duration-transition", mbgl::underlying_type(Property::RasterFadeDurationTransition)}, - {"raster-hue-rotate-transition", mbgl::underlying_type(Property::RasterHueRotateTransition)}, - {"raster-opacity-transition", mbgl::underlying_type(Property::RasterOpacityTransition)}, - {"raster-resampling-transition", mbgl::underlying_type(Property::RasterResamplingTransition)}, - {"raster-saturation-transition", mbgl::underlying_type(Property::RasterSaturationTransition)}}); + {{"raster-brightness-max", toUint8(Property::RasterBrightnessMax)}, + {"raster-brightness-min", toUint8(Property::RasterBrightnessMin)}, + {"raster-contrast", toUint8(Property::RasterContrast)}, + {"raster-fade-duration", toUint8(Property::RasterFadeDuration)}, + {"raster-hue-rotate", toUint8(Property::RasterHueRotate)}, + {"raster-opacity", toUint8(Property::RasterOpacity)}, + {"raster-resampling", toUint8(Property::RasterResampling)}, + {"raster-saturation", toUint8(Property::RasterSaturation)}, + {"raster-brightness-max-transition", toUint8(Property::RasterBrightnessMaxTransition)}, + {"raster-brightness-min-transition", toUint8(Property::RasterBrightnessMinTransition)}, + {"raster-contrast-transition", toUint8(Property::RasterContrastTransition)}, + {"raster-fade-duration-transition", toUint8(Property::RasterFadeDurationTransition)}, + {"raster-hue-rotate-transition", toUint8(Property::RasterHueRotateTransition)}, + {"raster-opacity-transition", toUint8(Property::RasterOpacityTransition)}, + {"raster-resampling-transition", toUint8(Property::RasterResamplingTransition)}, + {"raster-saturation-transition", toUint8(Property::RasterSaturationTransition)}}); } // namespace optional RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -395,49 +400,48 @@ optional RasterLayer::setPaintProperty(const std::string& name, const Con if (!transition) { return error; } - + if (property == Property::RasterBrightnessMaxTransition) { setRasterBrightnessMaxTransition(*transition); return nullopt; } - + if (property == Property::RasterBrightnessMinTransition) { setRasterBrightnessMinTransition(*transition); return nullopt; } - + if (property == Property::RasterContrastTransition) { setRasterContrastTransition(*transition); return nullopt; } - + if (property == Property::RasterFadeDurationTransition) { setRasterFadeDurationTransition(*transition); return nullopt; } - + if (property == Property::RasterHueRotateTransition) { setRasterHueRotateTransition(*transition); return nullopt; } - + if (property == Property::RasterOpacityTransition) { setRasterOpacityTransition(*transition); return nullopt; } - + if (property == Property::RasterResamplingTransition) { setRasterResamplingTransition(*transition); return nullopt; } - + if (property == Property::RasterSaturationTransition) { setRasterSaturationTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty RasterLayer::getPaintProperty(const std::string& name) const { @@ -448,37 +452,37 @@ LayerProperty RasterLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::RasterBrightnessMax: - return conversion::makeLayerProperty(getRasterBrightnessMax()); + return makeLayerProperty(getRasterBrightnessMax()); case Property::RasterBrightnessMin: - return conversion::makeLayerProperty(getRasterBrightnessMin()); + return makeLayerProperty(getRasterBrightnessMin()); case Property::RasterContrast: - return conversion::makeLayerProperty(getRasterContrast()); + return makeLayerProperty(getRasterContrast()); case Property::RasterFadeDuration: - return conversion::makeLayerProperty(getRasterFadeDuration()); + return makeLayerProperty(getRasterFadeDuration()); case Property::RasterHueRotate: - return conversion::makeLayerProperty(getRasterHueRotate()); + return makeLayerProperty(getRasterHueRotate()); case Property::RasterOpacity: - return conversion::makeLayerProperty(getRasterOpacity()); + return makeLayerProperty(getRasterOpacity()); case Property::RasterResampling: - return conversion::makeLayerProperty(getRasterResampling()); + return makeLayerProperty(getRasterResampling()); case Property::RasterSaturation: - return conversion::makeLayerProperty(getRasterSaturation()); + return makeLayerProperty(getRasterSaturation()); case Property::RasterBrightnessMaxTransition: - return conversion::makeLayerProperty(getRasterBrightnessMaxTransition()); + return makeLayerProperty(getRasterBrightnessMaxTransition()); case Property::RasterBrightnessMinTransition: - return conversion::makeLayerProperty(getRasterBrightnessMinTransition()); + return makeLayerProperty(getRasterBrightnessMinTransition()); case Property::RasterContrastTransition: - return conversion::makeLayerProperty(getRasterContrastTransition()); + return makeLayerProperty(getRasterContrastTransition()); case Property::RasterFadeDurationTransition: - return conversion::makeLayerProperty(getRasterFadeDurationTransition()); + return makeLayerProperty(getRasterFadeDurationTransition()); case Property::RasterHueRotateTransition: - return conversion::makeLayerProperty(getRasterHueRotateTransition()); + return makeLayerProperty(getRasterHueRotateTransition()); case Property::RasterOpacityTransition: - return conversion::makeLayerProperty(getRasterOpacityTransition()); + return makeLayerProperty(getRasterOpacityTransition()); case Property::RasterResamplingTransition: - return conversion::makeLayerProperty(getRasterResamplingTransition()); + return makeLayerProperty(getRasterResamplingTransition()); case Property::RasterSaturationTransition: - return conversion::makeLayerProperty(getRasterSaturationTransition()); + return makeLayerProperty(getRasterSaturationTransition()); } return {}; } diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index b36c02e558..48ecc245c5 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1135,42 +1135,47 @@ enum class Property { TextTranslateAnchorTransition, }; +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( - {{"icon-color", mbgl::underlying_type(Property::IconColor)}, - {"icon-halo-blur", mbgl::underlying_type(Property::IconHaloBlur)}, - {"icon-halo-color", mbgl::underlying_type(Property::IconHaloColor)}, - {"icon-halo-width", mbgl::underlying_type(Property::IconHaloWidth)}, - {"icon-opacity", mbgl::underlying_type(Property::IconOpacity)}, - {"icon-translate", mbgl::underlying_type(Property::IconTranslate)}, - {"icon-translate-anchor", mbgl::underlying_type(Property::IconTranslateAnchor)}, - {"text-color", mbgl::underlying_type(Property::TextColor)}, - {"text-halo-blur", mbgl::underlying_type(Property::TextHaloBlur)}, - {"text-halo-color", mbgl::underlying_type(Property::TextHaloColor)}, - {"text-halo-width", mbgl::underlying_type(Property::TextHaloWidth)}, - {"text-opacity", mbgl::underlying_type(Property::TextOpacity)}, - {"text-translate", mbgl::underlying_type(Property::TextTranslate)}, - {"text-translate-anchor", mbgl::underlying_type(Property::TextTranslateAnchor)}, - {"icon-color-transition", mbgl::underlying_type(Property::IconColorTransition)}, - {"icon-halo-blur-transition", mbgl::underlying_type(Property::IconHaloBlurTransition)}, - {"icon-halo-color-transition", mbgl::underlying_type(Property::IconHaloColorTransition)}, - {"icon-halo-width-transition", mbgl::underlying_type(Property::IconHaloWidthTransition)}, - {"icon-opacity-transition", mbgl::underlying_type(Property::IconOpacityTransition)}, - {"icon-translate-transition", mbgl::underlying_type(Property::IconTranslateTransition)}, - {"icon-translate-anchor-transition", mbgl::underlying_type(Property::IconTranslateAnchorTransition)}, - {"text-color-transition", mbgl::underlying_type(Property::TextColorTransition)}, - {"text-halo-blur-transition", mbgl::underlying_type(Property::TextHaloBlurTransition)}, - {"text-halo-color-transition", mbgl::underlying_type(Property::TextHaloColorTransition)}, - {"text-halo-width-transition", mbgl::underlying_type(Property::TextHaloWidthTransition)}, - {"text-opacity-transition", mbgl::underlying_type(Property::TextOpacityTransition)}, - {"text-translate-transition", mbgl::underlying_type(Property::TextTranslateTransition)}, - {"text-translate-anchor-transition", mbgl::underlying_type(Property::TextTranslateAnchorTransition)}}); + {{"icon-color", toUint8(Property::IconColor)}, + {"icon-halo-blur", toUint8(Property::IconHaloBlur)}, + {"icon-halo-color", toUint8(Property::IconHaloColor)}, + {"icon-halo-width", toUint8(Property::IconHaloWidth)}, + {"icon-opacity", toUint8(Property::IconOpacity)}, + {"icon-translate", toUint8(Property::IconTranslate)}, + {"icon-translate-anchor", toUint8(Property::IconTranslateAnchor)}, + {"text-color", toUint8(Property::TextColor)}, + {"text-halo-blur", toUint8(Property::TextHaloBlur)}, + {"text-halo-color", toUint8(Property::TextHaloColor)}, + {"text-halo-width", toUint8(Property::TextHaloWidth)}, + {"text-opacity", toUint8(Property::TextOpacity)}, + {"text-translate", toUint8(Property::TextTranslate)}, + {"text-translate-anchor", toUint8(Property::TextTranslateAnchor)}, + {"icon-color-transition", toUint8(Property::IconColorTransition)}, + {"icon-halo-blur-transition", toUint8(Property::IconHaloBlurTransition)}, + {"icon-halo-color-transition", toUint8(Property::IconHaloColorTransition)}, + {"icon-halo-width-transition", toUint8(Property::IconHaloWidthTransition)}, + {"icon-opacity-transition", toUint8(Property::IconOpacityTransition)}, + {"icon-translate-transition", toUint8(Property::IconTranslateTransition)}, + {"icon-translate-anchor-transition", toUint8(Property::IconTranslateAnchorTransition)}, + {"text-color-transition", toUint8(Property::TextColorTransition)}, + {"text-halo-blur-transition", toUint8(Property::TextHaloBlurTransition)}, + {"text-halo-color-transition", toUint8(Property::TextHaloColorTransition)}, + {"text-halo-width-transition", toUint8(Property::TextHaloWidthTransition)}, + {"text-opacity-transition", toUint8(Property::TextOpacityTransition)}, + {"text-translate-transition", toUint8(Property::TextTranslateTransition)}, + {"text-translate-anchor-transition", toUint8(Property::TextTranslateAnchorTransition)}}); } // namespace optional SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } auto property = static_cast(it->second); @@ -1288,79 +1293,78 @@ optional SymbolLayer::setPaintProperty(const std::string& name, const Con if (!transition) { return error; } - + if (property == Property::IconColorTransition) { setIconColorTransition(*transition); return nullopt; } - + if (property == Property::IconHaloBlurTransition) { setIconHaloBlurTransition(*transition); return nullopt; } - + if (property == Property::IconHaloColorTransition) { setIconHaloColorTransition(*transition); return nullopt; } - + if (property == Property::IconHaloWidthTransition) { setIconHaloWidthTransition(*transition); return nullopt; } - + if (property == Property::IconOpacityTransition) { setIconOpacityTransition(*transition); return nullopt; } - + if (property == Property::IconTranslateTransition) { setIconTranslateTransition(*transition); return nullopt; } - + if (property == Property::IconTranslateAnchorTransition) { setIconTranslateAnchorTransition(*transition); return nullopt; } - + if (property == Property::TextColorTransition) { setTextColorTransition(*transition); return nullopt; } - + if (property == Property::TextHaloBlurTransition) { setTextHaloBlurTransition(*transition); return nullopt; } - + if (property == Property::TextHaloColorTransition) { setTextHaloColorTransition(*transition); return nullopt; } - + if (property == Property::TextHaloWidthTransition) { setTextHaloWidthTransition(*transition); return nullopt; } - + if (property == Property::TextOpacityTransition) { setTextOpacityTransition(*transition); return nullopt; } - + if (property == Property::TextTranslateTransition) { setTextTranslateTransition(*transition); return nullopt; } - + if (property == Property::TextTranslateAnchorTransition) { setTextTranslateAnchorTransition(*transition); return nullopt; } - - return Error { "layer doesn't support this property" }; + return Error{"layer doesn't support this property"}; } LayerProperty SymbolLayer::getPaintProperty(const std::string& name) const { @@ -1371,61 +1375,61 @@ LayerProperty SymbolLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::IconColor: - return conversion::makeLayerProperty(getIconColor()); + return makeLayerProperty(getIconColor()); case Property::IconHaloBlur: - return conversion::makeLayerProperty(getIconHaloBlur()); + return makeLayerProperty(getIconHaloBlur()); case Property::IconHaloColor: - return conversion::makeLayerProperty(getIconHaloColor()); + return makeLayerProperty(getIconHaloColor()); case Property::IconHaloWidth: - return conversion::makeLayerProperty(getIconHaloWidth()); + return makeLayerProperty(getIconHaloWidth()); case Property::IconOpacity: - return conversion::makeLayerProperty(getIconOpacity()); + return makeLayerProperty(getIconOpacity()); case Property::IconTranslate: - return conversion::makeLayerProperty(getIconTranslate()); + return makeLayerProperty(getIconTranslate()); case Property::IconTranslateAnchor: - return conversion::makeLayerProperty(getIconTranslateAnchor()); + return makeLayerProperty(getIconTranslateAnchor()); case Property::TextColor: - return conversion::makeLayerProperty(getTextColor()); + return makeLayerProperty(getTextColor()); case Property::TextHaloBlur: - return conversion::makeLayerProperty(getTextHaloBlur()); + return makeLayerProperty(getTextHaloBlur()); case Property::TextHaloColor: - return conversion::makeLayerProperty(getTextHaloColor()); + return makeLayerProperty(getTextHaloColor()); case Property::TextHaloWidth: - return conversion::makeLayerProperty(getTextHaloWidth()); + return makeLayerProperty(getTextHaloWidth()); case Property::TextOpacity: - return conversion::makeLayerProperty(getTextOpacity()); + return makeLayerProperty(getTextOpacity()); case Property::TextTranslate: - return conversion::makeLayerProperty(getTextTranslate()); + return makeLayerProperty(getTextTranslate()); case Property::TextTranslateAnchor: - return conversion::makeLayerProperty(getTextTranslateAnchor()); + return makeLayerProperty(getTextTranslateAnchor()); case Property::IconColorTransition: - return conversion::makeLayerProperty(getIconColorTransition()); + return makeLayerProperty(getIconColorTransition()); case Property::IconHaloBlurTransition: - return conversion::makeLayerProperty(getIconHaloBlurTransition()); + return makeLayerProperty(getIconHaloBlurTransition()); case Property::IconHaloColorTransition: - return conversion::makeLayerProperty(getIconHaloColorTransition()); + return makeLayerProperty(getIconHaloColorTransition()); case Property::IconHaloWidthTransition: - return conversion::makeLayerProperty(getIconHaloWidthTransition()); + return makeLayerProperty(getIconHaloWidthTransition()); case Property::IconOpacityTransition: - return conversion::makeLayerProperty(getIconOpacityTransition()); + return makeLayerProperty(getIconOpacityTransition()); case Property::IconTranslateTransition: - return conversion::makeLayerProperty(getIconTranslateTransition()); + return makeLayerProperty(getIconTranslateTransition()); case Property::IconTranslateAnchorTransition: - return conversion::makeLayerProperty(getIconTranslateAnchorTransition()); + return makeLayerProperty(getIconTranslateAnchorTransition()); case Property::TextColorTransition: - return conversion::makeLayerProperty(getTextColorTransition()); + return makeLayerProperty(getTextColorTransition()); case Property::TextHaloBlurTransition: - return conversion::makeLayerProperty(getTextHaloBlurTransition()); + return makeLayerProperty(getTextHaloBlurTransition()); case Property::TextHaloColorTransition: - return conversion::makeLayerProperty(getTextHaloColorTransition()); + return makeLayerProperty(getTextHaloColorTransition()); case Property::TextHaloWidthTransition: - return conversion::makeLayerProperty(getTextHaloWidthTransition()); + return makeLayerProperty(getTextHaloWidthTransition()); case Property::TextOpacityTransition: - return conversion::makeLayerProperty(getTextOpacityTransition()); + return makeLayerProperty(getTextOpacityTransition()); case Property::TextTranslateTransition: - return conversion::makeLayerProperty(getTextTranslateTransition()); + return makeLayerProperty(getTextTranslateTransition()); case Property::TextTranslateAnchorTransition: - return conversion::makeLayerProperty(getTextTranslateAnchorTransition()); + return makeLayerProperty(getTextTranslateAnchorTransition()); } return {}; } -- cgit v1.2.1 From b5862c212769ee1372e4005dd1b96d49b72171e3 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 25 Sep 2019 22:10:03 +0300 Subject: [core] Add Map.UniversalStyleGetter test --- test/map/map.test.cpp | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 09e1b92336..35bae779c4 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -926,4 +926,77 @@ TEST(Map, Issue15342) { }; test.runLoop.run(); +} + +TEST(Map, UniversalStyleGetter) { + MapTest<> test; + + test.map.getStyle().loadJSON(R"STYLE({ + "sources": { + "mapbox": { + "type": "vector", + "tiles": ["http://example.com/{z}-{x}-{y}.vector.pbf"] + } + }, + "layers": [{ + "id": "line", + "type": "line", + "source": "mapbox", + "paint": { + "line-color": "red", + "line-opacity": 0.5, + "line-width": ["get", "width"] + } + }] + })STYLE"); + + Layer* lineLayer = test.map.getStyle().getLayer("line"); + ASSERT_TRUE(lineLayer); + + LayerProperty nonexistent = lineLayer->getPaintProperty("nonexistent"); + ASSERT_FALSE(nonexistent.value); + EXPECT_EQ(LayerProperty::Kind::Undefined, nonexistent.kind); + + LayerProperty undefined = lineLayer->getPaintProperty("line-blur"); + ASSERT_FALSE(undefined.value); + EXPECT_EQ(LayerProperty::Kind::Undefined, undefined.kind); + + LayerProperty lineColor = lineLayer->getPaintProperty("line-color"); + ASSERT_TRUE(lineColor.value); + EXPECT_EQ(LayerProperty::Kind::Constant, lineColor.kind); + ASSERT_TRUE(lineColor.value.getObject()); + const auto& color = *(lineColor.value.getObject()); + EXPECT_EQ(1.0, *color.at("r").getDouble()); + EXPECT_EQ(0.0, *color.at("g").getDouble()); + EXPECT_EQ(0.0, *color.at("b").getDouble()); + EXPECT_EQ(1.0, *color.at("a").getDouble()); + + LayerProperty lineOpacity = lineLayer->getPaintProperty("line-opacity"); + ASSERT_TRUE(lineOpacity.value); + EXPECT_EQ(LayerProperty::Kind::Constant, lineOpacity.kind); + ASSERT_TRUE(lineOpacity.value.getDouble()); + EXPECT_EQ(0.5, *lineOpacity.value.getDouble()); + + LayerProperty lineOpacityTransition = lineLayer->getPaintProperty("line-opacity-transition"); + ASSERT_TRUE(lineOpacityTransition.value); + EXPECT_EQ(LayerProperty::Kind::Transition, lineOpacityTransition.kind); + ASSERT_TRUE(lineOpacityTransition.value.getArray()); + EXPECT_EQ(3u, lineOpacityTransition.value.getArray()->size()); + + LayerProperty lineWidth = lineLayer->getPaintProperty("line-width"); + ASSERT_TRUE(lineWidth.value); + EXPECT_EQ(LayerProperty::Kind::Expression, lineWidth.kind); + ASSERT_TRUE(lineWidth.value.getArray()); + + const auto& expression = *lineWidth.value.getArray(); + EXPECT_EQ(2u, expression.size()); + ASSERT_TRUE(expression[0].getString()); + EXPECT_EQ("number", *expression[0].getString()); + ASSERT_TRUE(expression[1].getArray()); + const auto& operation = *expression[1].getArray(); + EXPECT_EQ(2, operation.size()); + ASSERT_TRUE(operation[0].getString()); + EXPECT_EQ("get", *operation[0].getString()); + ASSERT_TRUE(operation[1].getString()); + EXPECT_EQ("width", *operation[1].getString()); } \ No newline at end of file -- cgit v1.2.1 From e78c31c4b53326f260a4274018b5cb98fac0dbb6 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 25 Sep 2019 23:31:56 +0300 Subject: [core] LayerProperty -> StyleProperty --- include/mbgl/style/conversion_impl.hpp | 20 ++++---- include/mbgl/style/layer.hpp | 8 +-- include/mbgl/style/layers/background_layer.hpp | 2 +- include/mbgl/style/layers/circle_layer.hpp | 2 +- include/mbgl/style/layers/custom_layer.hpp | 2 +- include/mbgl/style/layers/fill_extrusion_layer.hpp | 2 +- include/mbgl/style/layers/fill_layer.hpp | 2 +- include/mbgl/style/layers/heatmap_layer.hpp | 2 +- include/mbgl/style/layers/hillshade_layer.hpp | 2 +- include/mbgl/style/layers/layer.hpp.ejs | 2 +- include/mbgl/style/layers/line_layer.hpp | 2 +- include/mbgl/style/layers/raster_layer.hpp | 2 +- include/mbgl/style/layers/symbol_layer.hpp | 2 +- src/mbgl/style/layers/background_layer.cpp | 16 +++--- src/mbgl/style/layers/circle_layer.cpp | 48 ++++++++--------- src/mbgl/style/layers/custom_layer.cpp | 2 +- src/mbgl/style/layers/fill_extrusion_layer.cpp | 36 ++++++------- src/mbgl/style/layers/fill_layer.cpp | 32 ++++++------ src/mbgl/style/layers/heatmap_layer.cpp | 24 ++++----- src/mbgl/style/layers/hillshade_layer.cpp | 28 +++++----- src/mbgl/style/layers/layer.cpp.ejs | 8 +-- src/mbgl/style/layers/line_layer.cpp | 48 ++++++++--------- src/mbgl/style/layers/raster_layer.cpp | 36 ++++++------- src/mbgl/style/layers/symbol_layer.cpp | 60 +++++++++++----------- test/map/map.test.cpp | 24 ++++----- 25 files changed, 206 insertions(+), 206 deletions(-) diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 866eff9eb5..ebeeee1c79 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -349,22 +349,22 @@ Value makeValue(T&& arg) { } template -LayerProperty makeLayerProperty(const PropertyValue& value) { - return value.match([](const Undefined&) -> LayerProperty { return {}; }, - [](const T& t) -> LayerProperty { - return {makeValue(t), LayerProperty::Kind::Constant}; +StyleProperty makeStyleProperty(const PropertyValue& value) { + return value.match([](const Undefined&) -> StyleProperty { return {}; }, + [](const T& t) -> StyleProperty { + return {makeValue(t), StyleProperty::Kind::Constant}; }, - [](const PropertyExpression& fn) -> LayerProperty { - return {fn.getExpression().serialize(), LayerProperty::Kind::Expression}; + [](const PropertyExpression& fn) -> StyleProperty { + return {fn.getExpression().serialize(), StyleProperty::Kind::Expression}; }); } -inline LayerProperty makeLayerProperty(const TransitionOptions& value) { - return {makeValue(value), LayerProperty::Kind::Transition}; +inline StyleProperty makeStyleProperty(const TransitionOptions& value) { + return {makeValue(value), StyleProperty::Kind::Transition}; } -inline LayerProperty makeLayerProperty(const ColorRampPropertyValue& value) { - return {makeValue(value), LayerProperty::Kind::Expression}; +inline StyleProperty makeStyleProperty(const ColorRampPropertyValue& value) { + return {makeValue(value), StyleProperty::Kind::Expression}; } } // namespace conversion diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index 646bad898c..11fd429be9 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -66,10 +66,10 @@ struct LayerTypeInfo { const enum class TileKind : uint8_t { Geometry, Raster, RasterDEM, NotRequired } tileKind; }; -struct LayerProperty { +struct StyleProperty { enum class Kind : uint8_t { Undefined, Constant, Expression, Transition }; - LayerProperty(Value value_, Kind kind_) : value(std::move(value_)), kind(kind_) {} - LayerProperty() = default; + StyleProperty(Value value_, Kind kind_) : value(std::move(value_)), kind(kind_) {} + StyleProperty() = default; const Value value; const Kind kind = Kind::Undefined; }; @@ -123,7 +123,7 @@ public: const conversion::Convertible& value) = 0; optional setVisibility(const conversion::Convertible& value); - virtual LayerProperty getPaintProperty(const std::string&) const = 0; + virtual StyleProperty getPaintProperty(const std::string&) const = 0; // Private implementation // TODO : We should not have public mutable data members. diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp index 8caade26b0..ad40e49660 100644 --- a/include/mbgl/style/layers/background_layer.hpp +++ b/include/mbgl/style/layers/background_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp index be4fe5cee4..f0bd18a825 100644 --- a/include/mbgl/style/layers/circle_layer.hpp +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp index 9ae68c4fff..ad27226505 100644 --- a/include/mbgl/style/layers/custom_layer.hpp +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -71,7 +71,7 @@ public: // Dynamic properties optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string&) const final; + StyleProperty getPaintProperty(const std::string&) const final; // Private implementation class Impl; diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp index 63ccf369d4..f2a5284fb9 100644 --- a/include/mbgl/style/layers/fill_extrusion_layer.hpp +++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp index acf60cec0d..0f4ce02aea 100644 --- a/include/mbgl/style/layers/fill_layer.hpp +++ b/include/mbgl/style/layers/fill_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/heatmap_layer.hpp b/include/mbgl/style/layers/heatmap_layer.hpp index 7eb7bb8edd..233ed32e36 100644 --- a/include/mbgl/style/layers/heatmap_layer.hpp +++ b/include/mbgl/style/layers/heatmap_layer.hpp @@ -25,7 +25,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/hillshade_layer.hpp b/include/mbgl/style/layers/hillshade_layer.hpp index 7c8f6fa573..aaed4597dc 100644 --- a/include/mbgl/style/layers/hillshade_layer.hpp +++ b/include/mbgl/style/layers/hillshade_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index f678adeda7..20dcb86abd 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -40,7 +40,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; <% if (layoutProperties.length) { -%> // Layout properties diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp index a1c69e9475..410b518f7b 100644 --- a/include/mbgl/style/layers/line_layer.hpp +++ b/include/mbgl/style/layers/line_layer.hpp @@ -27,7 +27,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Layout properties diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp index e516e1a0fc..91dab175ec 100644 --- a/include/mbgl/style/layers/raster_layer.hpp +++ b/include/mbgl/style/layers/raster_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 578d7d1701..0c128f84a6 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -26,7 +26,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - LayerProperty getPaintProperty(const std::string& name) const final; + StyleProperty getPaintProperty(const std::string& name) const final; // Layout properties diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 735d653e85..0e9e95d51a 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -150,7 +150,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { BackgroundColor, BackgroundOpacity, BackgroundPattern, @@ -244,7 +244,7 @@ optional BackgroundLayer::setPaintProperty(const std::string& name, const return Error{"layer doesn't support this property"}; } -LayerProperty BackgroundLayer::getPaintProperty(const std::string& name) const { +StyleProperty BackgroundLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -252,17 +252,17 @@ LayerProperty BackgroundLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::BackgroundColor: - return makeLayerProperty(getBackgroundColor()); + return makeStyleProperty(getBackgroundColor()); case Property::BackgroundOpacity: - return makeLayerProperty(getBackgroundOpacity()); + return makeStyleProperty(getBackgroundOpacity()); case Property::BackgroundPattern: - return makeLayerProperty(getBackgroundPattern()); + return makeStyleProperty(getBackgroundPattern()); case Property::BackgroundColorTransition: - return makeLayerProperty(getBackgroundColorTransition()); + return makeStyleProperty(getBackgroundColorTransition()); case Property::BackgroundOpacityTransition: - return makeLayerProperty(getBackgroundOpacityTransition()); + return makeStyleProperty(getBackgroundOpacityTransition()); case Property::BackgroundPatternTransition: - return makeLayerProperty(getBackgroundPatternTransition()); + return makeStyleProperty(getBackgroundPatternTransition()); } return {}; } diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 73171713b8..8b5359149c 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -366,7 +366,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { CircleBlur, CircleColor, CircleOpacity, @@ -597,7 +597,7 @@ optional CircleLayer::setPaintProperty(const std::string& name, const Con return Error{"layer doesn't support this property"}; } -LayerProperty CircleLayer::getPaintProperty(const std::string& name) const { +StyleProperty CircleLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -605,49 +605,49 @@ LayerProperty CircleLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::CircleBlur: - return makeLayerProperty(getCircleBlur()); + return makeStyleProperty(getCircleBlur()); case Property::CircleColor: - return makeLayerProperty(getCircleColor()); + return makeStyleProperty(getCircleColor()); case Property::CircleOpacity: - return makeLayerProperty(getCircleOpacity()); + return makeStyleProperty(getCircleOpacity()); case Property::CirclePitchAlignment: - return makeLayerProperty(getCirclePitchAlignment()); + return makeStyleProperty(getCirclePitchAlignment()); case Property::CirclePitchScale: - return makeLayerProperty(getCirclePitchScale()); + return makeStyleProperty(getCirclePitchScale()); case Property::CircleRadius: - return makeLayerProperty(getCircleRadius()); + return makeStyleProperty(getCircleRadius()); case Property::CircleStrokeColor: - return makeLayerProperty(getCircleStrokeColor()); + return makeStyleProperty(getCircleStrokeColor()); case Property::CircleStrokeOpacity: - return makeLayerProperty(getCircleStrokeOpacity()); + return makeStyleProperty(getCircleStrokeOpacity()); case Property::CircleStrokeWidth: - return makeLayerProperty(getCircleStrokeWidth()); + return makeStyleProperty(getCircleStrokeWidth()); case Property::CircleTranslate: - return makeLayerProperty(getCircleTranslate()); + return makeStyleProperty(getCircleTranslate()); case Property::CircleTranslateAnchor: - return makeLayerProperty(getCircleTranslateAnchor()); + return makeStyleProperty(getCircleTranslateAnchor()); case Property::CircleBlurTransition: - return makeLayerProperty(getCircleBlurTransition()); + return makeStyleProperty(getCircleBlurTransition()); case Property::CircleColorTransition: - return makeLayerProperty(getCircleColorTransition()); + return makeStyleProperty(getCircleColorTransition()); case Property::CircleOpacityTransition: - return makeLayerProperty(getCircleOpacityTransition()); + return makeStyleProperty(getCircleOpacityTransition()); case Property::CirclePitchAlignmentTransition: - return makeLayerProperty(getCirclePitchAlignmentTransition()); + return makeStyleProperty(getCirclePitchAlignmentTransition()); case Property::CirclePitchScaleTransition: - return makeLayerProperty(getCirclePitchScaleTransition()); + return makeStyleProperty(getCirclePitchScaleTransition()); case Property::CircleRadiusTransition: - return makeLayerProperty(getCircleRadiusTransition()); + return makeStyleProperty(getCircleRadiusTransition()); case Property::CircleStrokeColorTransition: - return makeLayerProperty(getCircleStrokeColorTransition()); + return makeStyleProperty(getCircleStrokeColorTransition()); case Property::CircleStrokeOpacityTransition: - return makeLayerProperty(getCircleStrokeOpacityTransition()); + return makeStyleProperty(getCircleStrokeOpacityTransition()); case Property::CircleStrokeWidthTransition: - return makeLayerProperty(getCircleStrokeWidthTransition()); + return makeStyleProperty(getCircleStrokeWidthTransition()); case Property::CircleTranslateTransition: - return makeLayerProperty(getCircleTranslateTransition()); + return makeStyleProperty(getCircleTranslateTransition()); case Property::CircleTranslateAnchorTransition: - return makeLayerProperty(getCircleTranslateAnchorTransition()); + return makeStyleProperty(getCircleTranslateAnchorTransition()); } return {}; } diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index f96cc682e5..98ca68aa48 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -47,7 +47,7 @@ optional CustomLayer::setLayoutProperty(const std::string&, const Convert return Error { "layer doesn't support this property" }; } -LayerProperty CustomLayer::getPaintProperty(const std::string&) const { +StyleProperty CustomLayer::getPaintProperty(const std::string&) const { return {}; } diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 04206e670d..690d74b2f5 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -285,7 +285,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { FillExtrusionBase, FillExtrusionColor, FillExtrusionHeight, @@ -479,7 +479,7 @@ optional FillExtrusionLayer::setPaintProperty(const std::string& name, co return Error{"layer doesn't support this property"}; } -LayerProperty FillExtrusionLayer::getPaintProperty(const std::string& name) const { +StyleProperty FillExtrusionLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -487,37 +487,37 @@ LayerProperty FillExtrusionLayer::getPaintProperty(const std::string& name) cons switch (static_cast(it->second)) { case Property::FillExtrusionBase: - return makeLayerProperty(getFillExtrusionBase()); + return makeStyleProperty(getFillExtrusionBase()); case Property::FillExtrusionColor: - return makeLayerProperty(getFillExtrusionColor()); + return makeStyleProperty(getFillExtrusionColor()); case Property::FillExtrusionHeight: - return makeLayerProperty(getFillExtrusionHeight()); + return makeStyleProperty(getFillExtrusionHeight()); case Property::FillExtrusionOpacity: - return makeLayerProperty(getFillExtrusionOpacity()); + return makeStyleProperty(getFillExtrusionOpacity()); case Property::FillExtrusionPattern: - return makeLayerProperty(getFillExtrusionPattern()); + return makeStyleProperty(getFillExtrusionPattern()); case Property::FillExtrusionTranslate: - return makeLayerProperty(getFillExtrusionTranslate()); + return makeStyleProperty(getFillExtrusionTranslate()); case Property::FillExtrusionTranslateAnchor: - return makeLayerProperty(getFillExtrusionTranslateAnchor()); + return makeStyleProperty(getFillExtrusionTranslateAnchor()); case Property::FillExtrusionVerticalGradient: - return makeLayerProperty(getFillExtrusionVerticalGradient()); + return makeStyleProperty(getFillExtrusionVerticalGradient()); case Property::FillExtrusionBaseTransition: - return makeLayerProperty(getFillExtrusionBaseTransition()); + return makeStyleProperty(getFillExtrusionBaseTransition()); case Property::FillExtrusionColorTransition: - return makeLayerProperty(getFillExtrusionColorTransition()); + return makeStyleProperty(getFillExtrusionColorTransition()); case Property::FillExtrusionHeightTransition: - return makeLayerProperty(getFillExtrusionHeightTransition()); + return makeStyleProperty(getFillExtrusionHeightTransition()); case Property::FillExtrusionOpacityTransition: - return makeLayerProperty(getFillExtrusionOpacityTransition()); + return makeStyleProperty(getFillExtrusionOpacityTransition()); case Property::FillExtrusionPatternTransition: - return makeLayerProperty(getFillExtrusionPatternTransition()); + return makeStyleProperty(getFillExtrusionPatternTransition()); case Property::FillExtrusionTranslateTransition: - return makeLayerProperty(getFillExtrusionTranslateTransition()); + return makeStyleProperty(getFillExtrusionTranslateTransition()); case Property::FillExtrusionTranslateAnchorTransition: - return makeLayerProperty(getFillExtrusionTranslateAnchorTransition()); + return makeStyleProperty(getFillExtrusionTranslateAnchorTransition()); case Property::FillExtrusionVerticalGradientTransition: - return makeLayerProperty(getFillExtrusionVerticalGradientTransition()); + return makeStyleProperty(getFillExtrusionVerticalGradientTransition()); } return {}; } diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 25bf97bb6d..e4f2a8cc53 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -258,7 +258,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { FillAntialias, FillColor, FillOpacity, @@ -431,7 +431,7 @@ optional FillLayer::setPaintProperty(const std::string& name, const Conve return Error{"layer doesn't support this property"}; } -LayerProperty FillLayer::getPaintProperty(const std::string& name) const { +StyleProperty FillLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -439,33 +439,33 @@ LayerProperty FillLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::FillAntialias: - return makeLayerProperty(getFillAntialias()); + return makeStyleProperty(getFillAntialias()); case Property::FillColor: - return makeLayerProperty(getFillColor()); + return makeStyleProperty(getFillColor()); case Property::FillOpacity: - return makeLayerProperty(getFillOpacity()); + return makeStyleProperty(getFillOpacity()); case Property::FillOutlineColor: - return makeLayerProperty(getFillOutlineColor()); + return makeStyleProperty(getFillOutlineColor()); case Property::FillPattern: - return makeLayerProperty(getFillPattern()); + return makeStyleProperty(getFillPattern()); case Property::FillTranslate: - return makeLayerProperty(getFillTranslate()); + return makeStyleProperty(getFillTranslate()); case Property::FillTranslateAnchor: - return makeLayerProperty(getFillTranslateAnchor()); + return makeStyleProperty(getFillTranslateAnchor()); case Property::FillAntialiasTransition: - return makeLayerProperty(getFillAntialiasTransition()); + return makeStyleProperty(getFillAntialiasTransition()); case Property::FillColorTransition: - return makeLayerProperty(getFillColorTransition()); + return makeStyleProperty(getFillColorTransition()); case Property::FillOpacityTransition: - return makeLayerProperty(getFillOpacityTransition()); + return makeStyleProperty(getFillOpacityTransition()); case Property::FillOutlineColorTransition: - return makeLayerProperty(getFillOutlineColorTransition()); + return makeStyleProperty(getFillOutlineColorTransition()); case Property::FillPatternTransition: - return makeLayerProperty(getFillPatternTransition()); + return makeStyleProperty(getFillPatternTransition()); case Property::FillTranslateTransition: - return makeLayerProperty(getFillTranslateTransition()); + return makeStyleProperty(getFillTranslateTransition()); case Property::FillTranslateAnchorTransition: - return makeLayerProperty(getFillTranslateAnchorTransition()); + return makeStyleProperty(getFillTranslateAnchorTransition()); } return {}; } diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 3db78c4cf5..5cda778d0f 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -206,7 +206,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { HeatmapColor, HeatmapIntensity, HeatmapOpacity, @@ -332,7 +332,7 @@ optional HeatmapLayer::setPaintProperty(const std::string& name, const Co return Error{"layer doesn't support this property"}; } -LayerProperty HeatmapLayer::getPaintProperty(const std::string& name) const { +StyleProperty HeatmapLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -340,25 +340,25 @@ LayerProperty HeatmapLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::HeatmapColor: - return makeLayerProperty(getHeatmapColor()); + return makeStyleProperty(getHeatmapColor()); case Property::HeatmapIntensity: - return makeLayerProperty(getHeatmapIntensity()); + return makeStyleProperty(getHeatmapIntensity()); case Property::HeatmapOpacity: - return makeLayerProperty(getHeatmapOpacity()); + return makeStyleProperty(getHeatmapOpacity()); case Property::HeatmapRadius: - return makeLayerProperty(getHeatmapRadius()); + return makeStyleProperty(getHeatmapRadius()); case Property::HeatmapWeight: - return makeLayerProperty(getHeatmapWeight()); + return makeStyleProperty(getHeatmapWeight()); case Property::HeatmapColorTransition: - return makeLayerProperty(getHeatmapColorTransition()); + return makeStyleProperty(getHeatmapColorTransition()); case Property::HeatmapIntensityTransition: - return makeLayerProperty(getHeatmapIntensityTransition()); + return makeStyleProperty(getHeatmapIntensityTransition()); case Property::HeatmapOpacityTransition: - return makeLayerProperty(getHeatmapOpacityTransition()); + return makeStyleProperty(getHeatmapOpacityTransition()); case Property::HeatmapRadiusTransition: - return makeLayerProperty(getHeatmapRadiusTransition()); + return makeStyleProperty(getHeatmapRadiusTransition()); case Property::HeatmapWeightTransition: - return makeLayerProperty(getHeatmapWeightTransition()); + return makeStyleProperty(getHeatmapWeightTransition()); } return {}; } diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index bda125da4a..7e67409a35 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -231,7 +231,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { HillshadeAccentColor, HillshadeExaggeration, HillshadeHighlightColor, @@ -371,7 +371,7 @@ optional HillshadeLayer::setPaintProperty(const std::string& name, const return Error{"layer doesn't support this property"}; } -LayerProperty HillshadeLayer::getPaintProperty(const std::string& name) const { +StyleProperty HillshadeLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -379,29 +379,29 @@ LayerProperty HillshadeLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::HillshadeAccentColor: - return makeLayerProperty(getHillshadeAccentColor()); + return makeStyleProperty(getHillshadeAccentColor()); case Property::HillshadeExaggeration: - return makeLayerProperty(getHillshadeExaggeration()); + return makeStyleProperty(getHillshadeExaggeration()); case Property::HillshadeHighlightColor: - return makeLayerProperty(getHillshadeHighlightColor()); + return makeStyleProperty(getHillshadeHighlightColor()); case Property::HillshadeIlluminationAnchor: - return makeLayerProperty(getHillshadeIlluminationAnchor()); + return makeStyleProperty(getHillshadeIlluminationAnchor()); case Property::HillshadeIlluminationDirection: - return makeLayerProperty(getHillshadeIlluminationDirection()); + return makeStyleProperty(getHillshadeIlluminationDirection()); case Property::HillshadeShadowColor: - return makeLayerProperty(getHillshadeShadowColor()); + return makeStyleProperty(getHillshadeShadowColor()); case Property::HillshadeAccentColorTransition: - return makeLayerProperty(getHillshadeAccentColorTransition()); + return makeStyleProperty(getHillshadeAccentColorTransition()); case Property::HillshadeExaggerationTransition: - return makeLayerProperty(getHillshadeExaggerationTransition()); + return makeStyleProperty(getHillshadeExaggerationTransition()); case Property::HillshadeHighlightColorTransition: - return makeLayerProperty(getHillshadeHighlightColorTransition()); + return makeStyleProperty(getHillshadeHighlightColorTransition()); case Property::HillshadeIlluminationAnchorTransition: - return makeLayerProperty(getHillshadeIlluminationAnchorTransition()); + return makeStyleProperty(getHillshadeIlluminationAnchorTransition()); case Property::HillshadeIlluminationDirectionTransition: - return makeLayerProperty(getHillshadeIlluminationDirectionTransition()); + return makeStyleProperty(getHillshadeIlluminationDirectionTransition()); case Property::HillshadeShadowColorTransition: - return makeLayerProperty(getHillshadeShadowColorTransition()); + return makeStyleProperty(getHillshadeShadowColorTransition()); } return {}; } diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 81b04be267..723c2b87ca 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -192,7 +192,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { <% for (const property of paintProperties) { -%> <%- camelize(property.name) %>, <% } -%> @@ -265,7 +265,7 @@ optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& return Error{"layer doesn't support this property"}; } -LayerProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& name) const { +StyleProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -274,11 +274,11 @@ LayerProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& na switch (static_cast(it->second)) { <% for (const property of paintProperties) { -%> case Property::<%- camelize(property.name) %>: - return makeLayerProperty(get<%- camelize(property.name) %>()); + return makeStyleProperty(get<%- camelize(property.name) %>()); <% } -%> <% for (const property of paintProperties) { -%> case Property::<%- camelize(property.name) %>Transition: - return makeLayerProperty(get<%- camelize(property.name) %>Transition()); + return makeStyleProperty(get<%- camelize(property.name) %>Transition()); <% } -%> } return {}; diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index ee1cfe2966..96b84ee1c5 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -432,7 +432,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { LineBlur, LineColor, LineDasharray, @@ -668,7 +668,7 @@ optional LineLayer::setPaintProperty(const std::string& name, const Conve return Error{"layer doesn't support this property"}; } -LayerProperty LineLayer::getPaintProperty(const std::string& name) const { +StyleProperty LineLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -676,49 +676,49 @@ LayerProperty LineLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::LineBlur: - return makeLayerProperty(getLineBlur()); + return makeStyleProperty(getLineBlur()); case Property::LineColor: - return makeLayerProperty(getLineColor()); + return makeStyleProperty(getLineColor()); case Property::LineDasharray: - return makeLayerProperty(getLineDasharray()); + return makeStyleProperty(getLineDasharray()); case Property::LineGapWidth: - return makeLayerProperty(getLineGapWidth()); + return makeStyleProperty(getLineGapWidth()); case Property::LineGradient: - return makeLayerProperty(getLineGradient()); + return makeStyleProperty(getLineGradient()); case Property::LineOffset: - return makeLayerProperty(getLineOffset()); + return makeStyleProperty(getLineOffset()); case Property::LineOpacity: - return makeLayerProperty(getLineOpacity()); + return makeStyleProperty(getLineOpacity()); case Property::LinePattern: - return makeLayerProperty(getLinePattern()); + return makeStyleProperty(getLinePattern()); case Property::LineTranslate: - return makeLayerProperty(getLineTranslate()); + return makeStyleProperty(getLineTranslate()); case Property::LineTranslateAnchor: - return makeLayerProperty(getLineTranslateAnchor()); + return makeStyleProperty(getLineTranslateAnchor()); case Property::LineWidth: - return makeLayerProperty(getLineWidth()); + return makeStyleProperty(getLineWidth()); case Property::LineBlurTransition: - return makeLayerProperty(getLineBlurTransition()); + return makeStyleProperty(getLineBlurTransition()); case Property::LineColorTransition: - return makeLayerProperty(getLineColorTransition()); + return makeStyleProperty(getLineColorTransition()); case Property::LineDasharrayTransition: - return makeLayerProperty(getLineDasharrayTransition()); + return makeStyleProperty(getLineDasharrayTransition()); case Property::LineGapWidthTransition: - return makeLayerProperty(getLineGapWidthTransition()); + return makeStyleProperty(getLineGapWidthTransition()); case Property::LineGradientTransition: - return makeLayerProperty(getLineGradientTransition()); + return makeStyleProperty(getLineGradientTransition()); case Property::LineOffsetTransition: - return makeLayerProperty(getLineOffsetTransition()); + return makeStyleProperty(getLineOffsetTransition()); case Property::LineOpacityTransition: - return makeLayerProperty(getLineOpacityTransition()); + return makeStyleProperty(getLineOpacityTransition()); case Property::LinePatternTransition: - return makeLayerProperty(getLinePatternTransition()); + return makeStyleProperty(getLinePatternTransition()); case Property::LineTranslateTransition: - return makeLayerProperty(getLineTranslateTransition()); + return makeStyleProperty(getLineTranslateTransition()); case Property::LineTranslateAnchorTransition: - return makeLayerProperty(getLineTranslateAnchorTransition()); + return makeStyleProperty(getLineTranslateAnchorTransition()); case Property::LineWidthTransition: - return makeLayerProperty(getLineWidthTransition()); + return makeStyleProperty(getLineWidthTransition()); } return {}; } diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 263cc0e2f4..20640020e0 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -285,7 +285,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { RasterBrightnessMax, RasterBrightnessMin, RasterContrast, @@ -444,7 +444,7 @@ optional RasterLayer::setPaintProperty(const std::string& name, const Con return Error{"layer doesn't support this property"}; } -LayerProperty RasterLayer::getPaintProperty(const std::string& name) const { +StyleProperty RasterLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -452,37 +452,37 @@ LayerProperty RasterLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::RasterBrightnessMax: - return makeLayerProperty(getRasterBrightnessMax()); + return makeStyleProperty(getRasterBrightnessMax()); case Property::RasterBrightnessMin: - return makeLayerProperty(getRasterBrightnessMin()); + return makeStyleProperty(getRasterBrightnessMin()); case Property::RasterContrast: - return makeLayerProperty(getRasterContrast()); + return makeStyleProperty(getRasterContrast()); case Property::RasterFadeDuration: - return makeLayerProperty(getRasterFadeDuration()); + return makeStyleProperty(getRasterFadeDuration()); case Property::RasterHueRotate: - return makeLayerProperty(getRasterHueRotate()); + return makeStyleProperty(getRasterHueRotate()); case Property::RasterOpacity: - return makeLayerProperty(getRasterOpacity()); + return makeStyleProperty(getRasterOpacity()); case Property::RasterResampling: - return makeLayerProperty(getRasterResampling()); + return makeStyleProperty(getRasterResampling()); case Property::RasterSaturation: - return makeLayerProperty(getRasterSaturation()); + return makeStyleProperty(getRasterSaturation()); case Property::RasterBrightnessMaxTransition: - return makeLayerProperty(getRasterBrightnessMaxTransition()); + return makeStyleProperty(getRasterBrightnessMaxTransition()); case Property::RasterBrightnessMinTransition: - return makeLayerProperty(getRasterBrightnessMinTransition()); + return makeStyleProperty(getRasterBrightnessMinTransition()); case Property::RasterContrastTransition: - return makeLayerProperty(getRasterContrastTransition()); + return makeStyleProperty(getRasterContrastTransition()); case Property::RasterFadeDurationTransition: - return makeLayerProperty(getRasterFadeDurationTransition()); + return makeStyleProperty(getRasterFadeDurationTransition()); case Property::RasterHueRotateTransition: - return makeLayerProperty(getRasterHueRotateTransition()); + return makeStyleProperty(getRasterHueRotateTransition()); case Property::RasterOpacityTransition: - return makeLayerProperty(getRasterOpacityTransition()); + return makeStyleProperty(getRasterOpacityTransition()); case Property::RasterResamplingTransition: - return makeLayerProperty(getRasterResamplingTransition()); + return makeStyleProperty(getRasterResamplingTransition()); case Property::RasterSaturationTransition: - return makeLayerProperty(getRasterSaturationTransition()); + return makeStyleProperty(getRasterSaturationTransition()); } return {}; } diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 48ecc245c5..86c049e509 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1104,7 +1104,7 @@ using namespace conversion; namespace { -enum class Property { +enum class Property : uint8_t { IconColor, IconHaloBlur, IconHaloColor, @@ -1367,7 +1367,7 @@ optional SymbolLayer::setPaintProperty(const std::string& name, const Con return Error{"layer doesn't support this property"}; } -LayerProperty SymbolLayer::getPaintProperty(const std::string& name) const { +StyleProperty SymbolLayer::getPaintProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; @@ -1375,61 +1375,61 @@ LayerProperty SymbolLayer::getPaintProperty(const std::string& name) const { switch (static_cast(it->second)) { case Property::IconColor: - return makeLayerProperty(getIconColor()); + return makeStyleProperty(getIconColor()); case Property::IconHaloBlur: - return makeLayerProperty(getIconHaloBlur()); + return makeStyleProperty(getIconHaloBlur()); case Property::IconHaloColor: - return makeLayerProperty(getIconHaloColor()); + return makeStyleProperty(getIconHaloColor()); case Property::IconHaloWidth: - return makeLayerProperty(getIconHaloWidth()); + return makeStyleProperty(getIconHaloWidth()); case Property::IconOpacity: - return makeLayerProperty(getIconOpacity()); + return makeStyleProperty(getIconOpacity()); case Property::IconTranslate: - return makeLayerProperty(getIconTranslate()); + return makeStyleProperty(getIconTranslate()); case Property::IconTranslateAnchor: - return makeLayerProperty(getIconTranslateAnchor()); + return makeStyleProperty(getIconTranslateAnchor()); case Property::TextColor: - return makeLayerProperty(getTextColor()); + return makeStyleProperty(getTextColor()); case Property::TextHaloBlur: - return makeLayerProperty(getTextHaloBlur()); + return makeStyleProperty(getTextHaloBlur()); case Property::TextHaloColor: - return makeLayerProperty(getTextHaloColor()); + return makeStyleProperty(getTextHaloColor()); case Property::TextHaloWidth: - return makeLayerProperty(getTextHaloWidth()); + return makeStyleProperty(getTextHaloWidth()); case Property::TextOpacity: - return makeLayerProperty(getTextOpacity()); + return makeStyleProperty(getTextOpacity()); case Property::TextTranslate: - return makeLayerProperty(getTextTranslate()); + return makeStyleProperty(getTextTranslate()); case Property::TextTranslateAnchor: - return makeLayerProperty(getTextTranslateAnchor()); + return makeStyleProperty(getTextTranslateAnchor()); case Property::IconColorTransition: - return makeLayerProperty(getIconColorTransition()); + return makeStyleProperty(getIconColorTransition()); case Property::IconHaloBlurTransition: - return makeLayerProperty(getIconHaloBlurTransition()); + return makeStyleProperty(getIconHaloBlurTransition()); case Property::IconHaloColorTransition: - return makeLayerProperty(getIconHaloColorTransition()); + return makeStyleProperty(getIconHaloColorTransition()); case Property::IconHaloWidthTransition: - return makeLayerProperty(getIconHaloWidthTransition()); + return makeStyleProperty(getIconHaloWidthTransition()); case Property::IconOpacityTransition: - return makeLayerProperty(getIconOpacityTransition()); + return makeStyleProperty(getIconOpacityTransition()); case Property::IconTranslateTransition: - return makeLayerProperty(getIconTranslateTransition()); + return makeStyleProperty(getIconTranslateTransition()); case Property::IconTranslateAnchorTransition: - return makeLayerProperty(getIconTranslateAnchorTransition()); + return makeStyleProperty(getIconTranslateAnchorTransition()); case Property::TextColorTransition: - return makeLayerProperty(getTextColorTransition()); + return makeStyleProperty(getTextColorTransition()); case Property::TextHaloBlurTransition: - return makeLayerProperty(getTextHaloBlurTransition()); + return makeStyleProperty(getTextHaloBlurTransition()); case Property::TextHaloColorTransition: - return makeLayerProperty(getTextHaloColorTransition()); + return makeStyleProperty(getTextHaloColorTransition()); case Property::TextHaloWidthTransition: - return makeLayerProperty(getTextHaloWidthTransition()); + return makeStyleProperty(getTextHaloWidthTransition()); case Property::TextOpacityTransition: - return makeLayerProperty(getTextOpacityTransition()); + return makeStyleProperty(getTextOpacityTransition()); case Property::TextTranslateTransition: - return makeLayerProperty(getTextTranslateTransition()); + return makeStyleProperty(getTextTranslateTransition()); case Property::TextTranslateAnchorTransition: - return makeLayerProperty(getTextTranslateAnchorTransition()); + return makeStyleProperty(getTextTranslateAnchorTransition()); } return {}; } diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 35bae779c4..758d1fa7cd 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -953,17 +953,17 @@ TEST(Map, UniversalStyleGetter) { Layer* lineLayer = test.map.getStyle().getLayer("line"); ASSERT_TRUE(lineLayer); - LayerProperty nonexistent = lineLayer->getPaintProperty("nonexistent"); + StyleProperty nonexistent = lineLayer->getPaintProperty("nonexistent"); ASSERT_FALSE(nonexistent.value); - EXPECT_EQ(LayerProperty::Kind::Undefined, nonexistent.kind); + EXPECT_EQ(StyleProperty::Kind::Undefined, nonexistent.kind); - LayerProperty undefined = lineLayer->getPaintProperty("line-blur"); + StyleProperty undefined = lineLayer->getPaintProperty("line-blur"); ASSERT_FALSE(undefined.value); - EXPECT_EQ(LayerProperty::Kind::Undefined, undefined.kind); + EXPECT_EQ(StyleProperty::Kind::Undefined, undefined.kind); - LayerProperty lineColor = lineLayer->getPaintProperty("line-color"); + StyleProperty lineColor = lineLayer->getPaintProperty("line-color"); ASSERT_TRUE(lineColor.value); - EXPECT_EQ(LayerProperty::Kind::Constant, lineColor.kind); + EXPECT_EQ(StyleProperty::Kind::Constant, lineColor.kind); ASSERT_TRUE(lineColor.value.getObject()); const auto& color = *(lineColor.value.getObject()); EXPECT_EQ(1.0, *color.at("r").getDouble()); @@ -971,21 +971,21 @@ TEST(Map, UniversalStyleGetter) { EXPECT_EQ(0.0, *color.at("b").getDouble()); EXPECT_EQ(1.0, *color.at("a").getDouble()); - LayerProperty lineOpacity = lineLayer->getPaintProperty("line-opacity"); + StyleProperty lineOpacity = lineLayer->getPaintProperty("line-opacity"); ASSERT_TRUE(lineOpacity.value); - EXPECT_EQ(LayerProperty::Kind::Constant, lineOpacity.kind); + EXPECT_EQ(StyleProperty::Kind::Constant, lineOpacity.kind); ASSERT_TRUE(lineOpacity.value.getDouble()); EXPECT_EQ(0.5, *lineOpacity.value.getDouble()); - LayerProperty lineOpacityTransition = lineLayer->getPaintProperty("line-opacity-transition"); + StyleProperty lineOpacityTransition = lineLayer->getPaintProperty("line-opacity-transition"); ASSERT_TRUE(lineOpacityTransition.value); - EXPECT_EQ(LayerProperty::Kind::Transition, lineOpacityTransition.kind); + EXPECT_EQ(StyleProperty::Kind::Transition, lineOpacityTransition.kind); ASSERT_TRUE(lineOpacityTransition.value.getArray()); EXPECT_EQ(3u, lineOpacityTransition.value.getArray()->size()); - LayerProperty lineWidth = lineLayer->getPaintProperty("line-width"); + StyleProperty lineWidth = lineLayer->getPaintProperty("line-width"); ASSERT_TRUE(lineWidth.value); - EXPECT_EQ(LayerProperty::Kind::Expression, lineWidth.kind); + EXPECT_EQ(StyleProperty::Kind::Expression, lineWidth.kind); ASSERT_TRUE(lineWidth.value.getArray()); const auto& expression = *lineWidth.value.getArray(); -- cgit v1.2.1 From 1733e29f0ac7ffe7c1aa5bf54d8f710befcdd2ea Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 26 Sep 2019 14:43:11 +0300 Subject: [core] Separate header for StyleProperty --- include/mbgl/style/layer.hpp | 10 +--------- include/mbgl/style/style_property.hpp | 20 ++++++++++++++++++++ next/CMakeLists.txt | 1 + src/core-files.json | 1 + 4 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 include/mbgl/style/style_property.hpp diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index 11fd429be9..849cb436be 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -1,8 +1,8 @@ #pragma once #include +#include #include -#include #include #include @@ -66,14 +66,6 @@ struct LayerTypeInfo { const enum class TileKind : uint8_t { Geometry, Raster, RasterDEM, NotRequired } tileKind; }; -struct StyleProperty { - enum class Kind : uint8_t { Undefined, Constant, Expression, Transition }; - StyleProperty(Value value_, Kind kind_) : value(std::move(value_)), kind(kind_) {} - StyleProperty() = default; - const Value value; - const Kind kind = Kind::Undefined; -}; - /** * The runtime representation of a [layer](https://www.mapbox.com/mapbox-gl-style-spec/#layers) from the Mapbox Style * Specification. diff --git a/include/mbgl/style/style_property.hpp b/include/mbgl/style/style_property.hpp new file mode 100644 index 0000000000..43787c7919 --- /dev/null +++ b/include/mbgl/style/style_property.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace mbgl { +namespace style { + +/** + * @brief Generic representation of a style property. + */ +struct StyleProperty { + enum class Kind : uint8_t { Undefined, Constant, Expression, Transition }; + StyleProperty(Value value_, Kind kind_) : value(std::move(value_)), kind(kind_) {} + StyleProperty() = default; + const Value value; + const Kind kind = Kind::Undefined; +}; + +} // namespace style +} // namespace mbgl diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index dbf6c11918..df56f04b22 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -189,6 +189,7 @@ add_library( ${MBGL_ROOT}/include/mbgl/style/sources/raster_source.hpp ${MBGL_ROOT}/include/mbgl/style/sources/vector_source.hpp ${MBGL_ROOT}/include/mbgl/style/style.hpp + ${MBGL_ROOT}/include/mbgl/style/style_property.hpp ${MBGL_ROOT}/include/mbgl/style/transition_options.hpp ${MBGL_ROOT}/include/mbgl/style/types.hpp ${MBGL_ROOT}/include/mbgl/style/undefined.hpp diff --git a/src/core-files.json b/src/core-files.json index a460ab86df..e5fa493312 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -452,6 +452,7 @@ "mbgl/style/sources/raster_source.hpp": "include/mbgl/style/sources/raster_source.hpp", "mbgl/style/sources/vector_source.hpp": "include/mbgl/style/sources/vector_source.hpp", "mbgl/style/style.hpp": "include/mbgl/style/style.hpp", + "mbgl/style/style_property.hpp": "include/mbgl/style/style_property.hpp", "mbgl/style/transition_options.hpp": "include/mbgl/style/transition_options.hpp", "mbgl/style/types.hpp": "include/mbgl/style/types.hpp", "mbgl/style/undefined.hpp": "include/mbgl/style/undefined.hpp", -- cgit v1.2.1 From 34ab7be2251bc8f6afca29c7a2ce3b6f1bc7cb10 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 26 Sep 2019 14:58:00 +0300 Subject: [core] Layer::getPaintProperty() -> Layer::getProperty() --- include/mbgl/style/layer.hpp | 2 +- include/mbgl/style/layers/background_layer.hpp | 2 +- include/mbgl/style/layers/circle_layer.hpp | 2 +- include/mbgl/style/layers/custom_layer.hpp | 2 +- include/mbgl/style/layers/fill_extrusion_layer.hpp | 2 +- include/mbgl/style/layers/fill_layer.hpp | 2 +- include/mbgl/style/layers/heatmap_layer.hpp | 2 +- include/mbgl/style/layers/hillshade_layer.hpp | 2 +- include/mbgl/style/layers/layer.hpp.ejs | 2 +- include/mbgl/style/layers/line_layer.hpp | 2 +- include/mbgl/style/layers/raster_layer.hpp | 2 +- include/mbgl/style/layers/symbol_layer.hpp | 2 +- src/mbgl/style/layers/background_layer.cpp | 2 +- src/mbgl/style/layers/circle_layer.cpp | 2 +- src/mbgl/style/layers/custom_layer.cpp | 2 +- src/mbgl/style/layers/fill_extrusion_layer.cpp | 2 +- src/mbgl/style/layers/fill_layer.cpp | 2 +- src/mbgl/style/layers/heatmap_layer.cpp | 2 +- src/mbgl/style/layers/hillshade_layer.cpp | 2 +- src/mbgl/style/layers/layer.cpp.ejs | 2 +- src/mbgl/style/layers/line_layer.cpp | 2 +- src/mbgl/style/layers/raster_layer.cpp | 2 +- src/mbgl/style/layers/symbol_layer.cpp | 2 +- test/map/map.test.cpp | 12 ++++++------ 24 files changed, 29 insertions(+), 29 deletions(-) diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index 849cb436be..b50ca75067 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -115,7 +115,7 @@ public: const conversion::Convertible& value) = 0; optional setVisibility(const conversion::Convertible& value); - virtual StyleProperty getPaintProperty(const std::string&) const = 0; + virtual StyleProperty getProperty(const std::string&) const = 0; // Private implementation // TODO : We should not have public mutable data members. diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp index ad40e49660..ebdce35d0f 100644 --- a/include/mbgl/style/layers/background_layer.hpp +++ b/include/mbgl/style/layers/background_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp index f0bd18a825..842094f944 100644 --- a/include/mbgl/style/layers/circle_layer.hpp +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp index ad27226505..c193cfb8d9 100644 --- a/include/mbgl/style/layers/custom_layer.hpp +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -71,7 +71,7 @@ public: // Dynamic properties optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string&) const final; + StyleProperty getProperty(const std::string&) const final; // Private implementation class Impl; diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp index f2a5284fb9..76c2359617 100644 --- a/include/mbgl/style/layers/fill_extrusion_layer.hpp +++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp index 0f4ce02aea..9ec33d7e96 100644 --- a/include/mbgl/style/layers/fill_layer.hpp +++ b/include/mbgl/style/layers/fill_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/heatmap_layer.hpp b/include/mbgl/style/layers/heatmap_layer.hpp index 233ed32e36..2dec03b927 100644 --- a/include/mbgl/style/layers/heatmap_layer.hpp +++ b/include/mbgl/style/layers/heatmap_layer.hpp @@ -25,7 +25,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/hillshade_layer.hpp b/include/mbgl/style/layers/hillshade_layer.hpp index aaed4597dc..824606c29b 100644 --- a/include/mbgl/style/layers/hillshade_layer.hpp +++ b/include/mbgl/style/layers/hillshade_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index 20dcb86abd..7b60fcf6ea 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -40,7 +40,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; <% if (layoutProperties.length) { -%> // Layout properties diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp index 410b518f7b..4f2cf53708 100644 --- a/include/mbgl/style/layers/line_layer.hpp +++ b/include/mbgl/style/layers/line_layer.hpp @@ -27,7 +27,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Layout properties diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp index 91dab175ec..bff38d42ac 100644 --- a/include/mbgl/style/layers/raster_layer.hpp +++ b/include/mbgl/style/layers/raster_layer.hpp @@ -24,7 +24,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Paint properties diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 0c128f84a6..92e214919a 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -26,7 +26,7 @@ public: optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; - StyleProperty getPaintProperty(const std::string& name) const final; + StyleProperty getProperty(const std::string& name) const final; // Layout properties diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 0e9e95d51a..0a83af537c 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -244,7 +244,7 @@ optional BackgroundLayer::setPaintProperty(const std::string& name, const return Error{"layer doesn't support this property"}; } -StyleProperty BackgroundLayer::getPaintProperty(const std::string& name) const { +StyleProperty BackgroundLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 8b5359149c..f174aacadb 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -597,7 +597,7 @@ optional CircleLayer::setPaintProperty(const std::string& name, const Con return Error{"layer doesn't support this property"}; } -StyleProperty CircleLayer::getPaintProperty(const std::string& name) const { +StyleProperty CircleLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index 98ca68aa48..e13cf0069a 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -47,7 +47,7 @@ optional CustomLayer::setLayoutProperty(const std::string&, const Convert return Error { "layer doesn't support this property" }; } -StyleProperty CustomLayer::getPaintProperty(const std::string&) const { +StyleProperty CustomLayer::getProperty(const std::string&) const { return {}; } diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 690d74b2f5..a24ea6416a 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -479,7 +479,7 @@ optional FillExtrusionLayer::setPaintProperty(const std::string& name, co return Error{"layer doesn't support this property"}; } -StyleProperty FillExtrusionLayer::getPaintProperty(const std::string& name) const { +StyleProperty FillExtrusionLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index e4f2a8cc53..6b4b15f83f 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -431,7 +431,7 @@ optional FillLayer::setPaintProperty(const std::string& name, const Conve return Error{"layer doesn't support this property"}; } -StyleProperty FillLayer::getPaintProperty(const std::string& name) const { +StyleProperty FillLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 5cda778d0f..f1da87928d 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -332,7 +332,7 @@ optional HeatmapLayer::setPaintProperty(const std::string& name, const Co return Error{"layer doesn't support this property"}; } -StyleProperty HeatmapLayer::getPaintProperty(const std::string& name) const { +StyleProperty HeatmapLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 7e67409a35..28a3d903da 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -371,7 +371,7 @@ optional HillshadeLayer::setPaintProperty(const std::string& name, const return Error{"layer doesn't support this property"}; } -StyleProperty HillshadeLayer::getPaintProperty(const std::string& name) const { +StyleProperty HillshadeLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 723c2b87ca..69f7ed1765 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -265,7 +265,7 @@ optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& return Error{"layer doesn't support this property"}; } -StyleProperty <%- camelize(type) %>Layer::getPaintProperty(const std::string& name) const { +StyleProperty <%- camelize(type) %>Layer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 96b84ee1c5..da2c801e10 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -668,7 +668,7 @@ optional LineLayer::setPaintProperty(const std::string& name, const Conve return Error{"layer doesn't support this property"}; } -StyleProperty LineLayer::getPaintProperty(const std::string& name) const { +StyleProperty LineLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 20640020e0..2e548dfa5b 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -444,7 +444,7 @@ optional RasterLayer::setPaintProperty(const std::string& name, const Con return Error{"layer doesn't support this property"}; } -StyleProperty RasterLayer::getPaintProperty(const std::string& name) const { +StyleProperty RasterLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 86c049e509..50906c51e2 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1367,7 +1367,7 @@ optional SymbolLayer::setPaintProperty(const std::string& name, const Con return Error{"layer doesn't support this property"}; } -StyleProperty SymbolLayer::getPaintProperty(const std::string& name) const { +StyleProperty SymbolLayer::getProperty(const std::string& name) const { const auto it = paintProperties.find(name.c_str()); if (it == paintProperties.end()) { return {}; diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 758d1fa7cd..7293c1c6ca 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -953,15 +953,15 @@ TEST(Map, UniversalStyleGetter) { Layer* lineLayer = test.map.getStyle().getLayer("line"); ASSERT_TRUE(lineLayer); - StyleProperty nonexistent = lineLayer->getPaintProperty("nonexistent"); + StyleProperty nonexistent = lineLayer->getProperty("nonexistent"); ASSERT_FALSE(nonexistent.value); EXPECT_EQ(StyleProperty::Kind::Undefined, nonexistent.kind); - StyleProperty undefined = lineLayer->getPaintProperty("line-blur"); + StyleProperty undefined = lineLayer->getProperty("line-blur"); ASSERT_FALSE(undefined.value); EXPECT_EQ(StyleProperty::Kind::Undefined, undefined.kind); - StyleProperty lineColor = lineLayer->getPaintProperty("line-color"); + StyleProperty lineColor = lineLayer->getProperty("line-color"); ASSERT_TRUE(lineColor.value); EXPECT_EQ(StyleProperty::Kind::Constant, lineColor.kind); ASSERT_TRUE(lineColor.value.getObject()); @@ -971,19 +971,19 @@ TEST(Map, UniversalStyleGetter) { EXPECT_EQ(0.0, *color.at("b").getDouble()); EXPECT_EQ(1.0, *color.at("a").getDouble()); - StyleProperty lineOpacity = lineLayer->getPaintProperty("line-opacity"); + StyleProperty lineOpacity = lineLayer->getProperty("line-opacity"); ASSERT_TRUE(lineOpacity.value); EXPECT_EQ(StyleProperty::Kind::Constant, lineOpacity.kind); ASSERT_TRUE(lineOpacity.value.getDouble()); EXPECT_EQ(0.5, *lineOpacity.value.getDouble()); - StyleProperty lineOpacityTransition = lineLayer->getPaintProperty("line-opacity-transition"); + StyleProperty lineOpacityTransition = lineLayer->getProperty("line-opacity-transition"); ASSERT_TRUE(lineOpacityTransition.value); EXPECT_EQ(StyleProperty::Kind::Transition, lineOpacityTransition.kind); ASSERT_TRUE(lineOpacityTransition.value.getArray()); EXPECT_EQ(3u, lineOpacityTransition.value.getArray()->size()); - StyleProperty lineWidth = lineLayer->getPaintProperty("line-width"); + StyleProperty lineWidth = lineLayer->getProperty("line-width"); ASSERT_TRUE(lineWidth.value); EXPECT_EQ(StyleProperty::Kind::Expression, lineWidth.kind); ASSERT_TRUE(lineWidth.value.getArray()); -- cgit v1.2.1 From f3146e43cd19bdf85957d6d62132ac7c31eacc50 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 26 Sep 2019 17:53:49 +0300 Subject: [core] ValueFactory for `expression::formatted`, other improvements --- expression-test/expression_test_parser.cpp | 28 +--------------------------- include/mbgl/style/conversion.hpp | 5 ++++- include/mbgl/style/conversion_impl.hpp | 29 ++++++++++++++--------------- include/mbgl/style/expression/formatted.hpp | 16 +++++++++++----- include/mbgl/util/traits.hpp | 10 ++++++++++ src/mbgl/style/expression/formatted.cpp | 29 +++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 48 deletions(-) diff --git a/expression-test/expression_test_parser.cpp b/expression-test/expression_test_parser.cpp index 3c194ffee0..546a96b3e0 100644 --- a/expression-test/expression_test_parser.cpp +++ b/expression-test/expression_test_parser.cpp @@ -439,33 +439,7 @@ optional toValue(const expression::Value& exprValue) { std::vector color { double(c.r), double(c.g), double(c.b), double(c.a) }; return {Value{std::move(color)}}; }, - [](const expression::Formatted& formatted) -> optional { - std::unordered_map serialized; - std::vector sections; - for (const auto& section : formatted.sections) { - std::unordered_map serializedSection; - serializedSection.emplace("text", section.text); - if (section.fontScale) { - serializedSection.emplace("scale", *section.fontScale); - } else { - serializedSection.emplace("scale", NullValue()); - } - if (section.fontStack) { - std::string fontStackString; - serializedSection.emplace("fontStack", fontStackToString(*section.fontStack)); - } else { - serializedSection.emplace("fontStack", NullValue()); - } - if (section.textColor) { - serializedSection.emplace("textColor", section.textColor->toObject()); - } else { - serializedSection.emplace("textColor", NullValue()); - } - sections.emplace_back(serializedSection); - } - serialized.emplace("sections", sections); - return {Value{std::move(serialized)}}; - }, + [](const expression::Formatted& formatted) -> optional { return {formatted.toObject()}; }, [](const std::vector& values) -> optional { std::vector mbglValues; for (const auto& value : values) { diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 2c83d1561b..29af9fac91 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -17,9 +17,12 @@ class ConversionTraits; class Convertible; -template +template struct Converter; +template +struct ValueFactory; + } // namespace conversion } // namespace style } // namespace mbgl diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index ebeeee1c79..7abe7bf923 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -297,20 +298,6 @@ optional convert(const Convertible& value, Error& error, Args&&...args) { return Converter()(value, error, std::forward(args)...); } -template -struct ValueFactory; - -template -struct ValueArrayFactory { - static Value make(const T& arg) { return mapbox::base::ValueArray(arg.begin(), arg.end()); } -}; - -template <> -struct ValueFactory> : public ValueArrayFactory> {}; - -template <> -struct ValueFactory> : public ValueArrayFactory> {}; - template <> struct ValueFactory { static Value make(const ColorRampPropertyValue& value) { return value.getExpression().serialize(); } @@ -334,7 +321,7 @@ struct ValueFactory { }; template -struct ValueFactory::value>::type> { +struct ValueFactory::value && !is_linear_container::value)>::type> { static Value make(const T& arg) { return {arg}; } }; @@ -343,6 +330,18 @@ struct ValueFactory::value>::type> { static Value make(T arg) { return {int64_t(arg)}; } }; +template +struct ValueFactory::value>::type> { + static Value make(const T& arg) { + mapbox::base::ValueArray result; + result.reserve(arg.size()); + for (const auto& item : arg) { + result.emplace_back(ValueFactory>::make(item)); + } + return result; + } +}; + template Value makeValue(T&& arg) { return ValueFactory>::make(std::forward(arg)); diff --git a/include/mbgl/style/expression/formatted.hpp b/include/mbgl/style/expression/formatted.hpp index f4f08e9197..bb3d609c91 100644 --- a/include/mbgl/style/expression/formatted.hpp +++ b/include/mbgl/style/expression/formatted.hpp @@ -48,7 +48,8 @@ public: bool operator==(const Formatted& ) const; std::string toString() const; - + mbgl::Value toObject() const; + bool empty() const { return sections.empty() || sections.at(0).text.empty(); } @@ -59,13 +60,18 @@ public: } // namespace expression namespace conversion { - + template <> -struct Converter { +struct Converter { public: - optional operator()(const Convertible& value, Error& error) const; + optional operator()(const Convertible& value, Error& error) const; }; - + +template <> +struct ValueFactory { + static Value make(const expression::Formatted& formatted) { return formatted.toObject(); } +}; + } // namespace conversion } // namespace style diff --git a/include/mbgl/util/traits.hpp b/include/mbgl/util/traits.hpp index 5b9401aad7..e37144e60e 100644 --- a/include/mbgl/util/traits.hpp +++ b/include/mbgl/util/traits.hpp @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include namespace mbgl { @@ -25,4 +27,12 @@ typename std::enable_if::value && is_utf16char_like_po return reinterpret_cast(in); } +template +struct is_linear_container : std::false_type {}; + +template +struct is_linear_container> : std::true_type {}; +template +struct is_linear_container> : std::true_type {}; + } // namespace mbgl diff --git a/src/mbgl/style/expression/formatted.cpp b/src/mbgl/style/expression/formatted.cpp index 5d45806ecb..4591a50ed1 100644 --- a/src/mbgl/style/expression/formatted.cpp +++ b/src/mbgl/style/expression/formatted.cpp @@ -35,6 +35,35 @@ std::string Formatted::toString() const { return result; } +mbgl::Value Formatted::toObject() const { + mapbox::base::ValueObject result; + mapbox::base::ValueArray sectionValues; + sectionValues.reserve(sections.size()); + for (const auto& section : sections) { + mapbox::base::ValueObject serializedSection; + serializedSection.emplace("text", section.text); + if (section.fontScale) { + serializedSection.emplace("scale", *section.fontScale); + } else { + serializedSection.emplace("scale", NullValue()); + } + if (section.fontStack) { + std::string fontStackString; + serializedSection.emplace("fontStack", fontStackToString(*section.fontStack)); + } else { + serializedSection.emplace("fontStack", NullValue()); + } + if (section.textColor) { + serializedSection.emplace("textColor", section.textColor->toObject()); + } else { + serializedSection.emplace("textColor", NullValue()); + } + sectionValues.emplace_back(serializedSection); + } + result.emplace("sections", std::move(sectionValues)); + return result; +} + } // namespace expression namespace conversion { -- cgit v1.2.1 From 5304bbc438afd60853c97d74cd38f04a50effa06 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 26 Sep 2019 17:58:58 +0300 Subject: [core] Layer::getProperty supports layout properties --- src/mbgl/style/layers/background_layer.cpp | 15 +- src/mbgl/style/layers/circle_layer.cpp | 15 +- src/mbgl/style/layers/fill_extrusion_layer.cpp | 15 +- src/mbgl/style/layers/fill_layer.cpp | 15 +- src/mbgl/style/layers/heatmap_layer.cpp | 15 +- src/mbgl/style/layers/hillshade_layer.cpp | 15 +- src/mbgl/style/layers/layer.cpp.ejs | 41 ++-- src/mbgl/style/layers/line_layer.cpp | 50 ++--- src/mbgl/style/layers/raster_layer.cpp | 15 +- src/mbgl/style/layers/symbol_layer.cpp | 274 ++++++++++++++++--------- test/map/map.test.cpp | 9 + 11 files changed, 271 insertions(+), 208 deletions(-) diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 0a83af537c..9187784452 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -164,7 +162,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"background-color", toUint8(Property::BackgroundColor)}, {"background-opacity", toUint8(Property::BackgroundOpacity)}, {"background-pattern", toUint8(Property::BackgroundPattern)}, @@ -172,11 +170,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"background-opacity-transition", toUint8(Property::BackgroundOpacityTransition)}, {"background-pattern-transition", toUint8(Property::BackgroundPatternTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::BackgroundPatternTransition); } // namespace optional BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -245,8 +244,8 @@ optional BackgroundLayer::setPaintProperty(const std::string& name, const } StyleProperty BackgroundLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -281,5 +280,3 @@ Mutable BackgroundLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index f174aacadb..145d76a9a8 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -396,7 +394,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"circle-blur", toUint8(Property::CircleBlur)}, {"circle-color", toUint8(Property::CircleColor)}, {"circle-opacity", toUint8(Property::CircleOpacity)}, @@ -420,11 +418,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"circle-translate-transition", toUint8(Property::CircleTranslateTransition)}, {"circle-translate-anchor-transition", toUint8(Property::CircleTranslateAnchorTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::CircleTranslateAnchorTransition); } // namespace optional CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -598,8 +597,8 @@ optional CircleLayer::setPaintProperty(const std::string& name, const Con } StyleProperty CircleLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -666,5 +665,3 @@ Mutable CircleLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index a24ea6416a..87e196926f 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -309,7 +307,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"fill-extrusion-base", toUint8(Property::FillExtrusionBase)}, {"fill-extrusion-color", toUint8(Property::FillExtrusionColor)}, {"fill-extrusion-height", toUint8(Property::FillExtrusionHeight)}, @@ -327,11 +325,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"fill-extrusion-translate-anchor-transition", toUint8(Property::FillExtrusionTranslateAnchorTransition)}, {"fill-extrusion-vertical-gradient-transition", toUint8(Property::FillExtrusionVerticalGradientTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::FillExtrusionVerticalGradientTransition); } // namespace optional FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -480,8 +479,8 @@ optional FillExtrusionLayer::setPaintProperty(const std::string& name, co } StyleProperty FillExtrusionLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -536,5 +535,3 @@ Mutable FillExtrusionLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 6b4b15f83f..e3d6c6c708 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -280,7 +278,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"fill-antialias", toUint8(Property::FillAntialias)}, {"fill-color", toUint8(Property::FillColor)}, {"fill-opacity", toUint8(Property::FillOpacity)}, @@ -296,11 +294,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"fill-translate-transition", toUint8(Property::FillTranslateTransition)}, {"fill-translate-anchor-transition", toUint8(Property::FillTranslateAnchorTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::FillTranslateAnchorTransition); } // namespace optional FillLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -432,8 +431,8 @@ optional FillLayer::setPaintProperty(const std::string& name, const Conve } StyleProperty FillLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -484,5 +483,3 @@ Mutable FillLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index f1da87928d..332c65c6b4 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -224,7 +222,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"heatmap-color", toUint8(Property::HeatmapColor)}, {"heatmap-intensity", toUint8(Property::HeatmapIntensity)}, {"heatmap-opacity", toUint8(Property::HeatmapOpacity)}, @@ -236,11 +234,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"heatmap-radius-transition", toUint8(Property::HeatmapRadiusTransition)}, {"heatmap-weight-transition", toUint8(Property::HeatmapWeightTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::HeatmapWeightTransition); } // namespace optional HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -333,8 +332,8 @@ optional HeatmapLayer::setPaintProperty(const std::string& name, const Co } StyleProperty HeatmapLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -377,5 +376,3 @@ Mutable HeatmapLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 28a3d903da..a55c079c49 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -251,7 +249,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"hillshade-accent-color", toUint8(Property::HillshadeAccentColor)}, {"hillshade-exaggeration", toUint8(Property::HillshadeExaggeration)}, {"hillshade-highlight-color", toUint8(Property::HillshadeHighlightColor)}, @@ -265,11 +263,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"hillshade-illumination-direction-transition", toUint8(Property::HillshadeIlluminationDirectionTransition)}, {"hillshade-shadow-color-transition", toUint8(Property::HillshadeShadowColorTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::HillshadeShadowColorTransition); } // namespace optional HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -372,8 +371,8 @@ optional HillshadeLayer::setPaintProperty(const std::string& name, const } StyleProperty HillshadeLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -420,5 +419,3 @@ Mutable HillshadeLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 69f7ed1765..775288264f 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -3,8 +3,6 @@ const layoutProperties = locals.layoutProperties; const paintProperties = locals.paintProperties; -%> -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include _layer.hpp> @@ -199,6 +197,9 @@ enum class Property : uint8_t { <% for (const property of paintProperties) { -%> <%- camelize(property.name) %>Transition, <% } -%> +<% for (const property of layoutProperties) { -%> + <%- camelize(property.name) %>, +<% } -%> }; template @@ -206,15 +207,22 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {<%- paintProperties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>, +<% if (!layoutProperties.length) { -%> <%- paintProperties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); +<% } else { -%> + <%- paintProperties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>, + <%- layoutProperties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>}); +<% } -%> +<% const lastPaintProperty = paintProperties[paintProperties.length - 1]; -%> +<%-`constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::${camelize(lastPaintProperty.name)}Transition);` %> } // namespace optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -266,8 +274,8 @@ optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& } StyleProperty <%- camelize(type) %>Layer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -279,6 +287,10 @@ StyleProperty <%- camelize(type) %>Layer::getProperty(const std::string& name) c <% for (const property of paintProperties) { -%> case Property::<%- camelize(property.name) %>Transition: return makeStyleProperty(get<%- camelize(property.name) %>Transition()); +<% } -%> +<% for (const property of layoutProperties) { -%> + case Property::<%- camelize(property.name) %>: + return makeStyleProperty(get<%- camelize(property.name) %>()); <% } -%> } return {}; @@ -289,17 +301,8 @@ optional <%- camelize(type) %>Layer::setLayoutProperty(const std::string& return Layer::setVisibility(value); } <% if (layoutProperties.length) { -%> - enum class Property { -<% for (const property of layoutProperties) { -%> - <%- camelize(property.name) %>, -<% } -%> - }; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - <%- layoutProperties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %> - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second <= lastPaintPropertyIndex) { return Error { "layer doesn't support this property" }; } @@ -345,5 +348,3 @@ Mutable <%- camelize(type) %>Layer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index da2c801e10..309a81ae2b 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -455,6 +453,10 @@ enum class Property : uint8_t { LineTranslateTransition, LineTranslateAnchorTransition, LineWidthTransition, + LineCap, + LineJoin, + LineMiterLimit, + LineRoundLimit, }; template @@ -462,7 +464,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"line-blur", toUint8(Property::LineBlur)}, {"line-color", toUint8(Property::LineColor)}, {"line-dasharray", toUint8(Property::LineDasharray)}, @@ -484,13 +486,18 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"line-pattern-transition", toUint8(Property::LinePatternTransition)}, {"line-translate-transition", toUint8(Property::LineTranslateTransition)}, {"line-translate-anchor-transition", toUint8(Property::LineTranslateAnchorTransition)}, - {"line-width-transition", toUint8(Property::LineWidthTransition)}}); + {"line-width-transition", toUint8(Property::LineWidthTransition)}, + {"line-cap", toUint8(Property::LineCap)}, + {"line-join", toUint8(Property::LineJoin)}, + {"line-miter-limit", toUint8(Property::LineMiterLimit)}, + {"line-round-limit", toUint8(Property::LineRoundLimit)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::LineWidthTransition); } // namespace optional LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -669,8 +676,8 @@ optional LineLayer::setPaintProperty(const std::string& name, const Conve } StyleProperty LineLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -719,6 +726,14 @@ StyleProperty LineLayer::getProperty(const std::string& name) const { return makeStyleProperty(getLineTranslateAnchorTransition()); case Property::LineWidthTransition: return makeStyleProperty(getLineWidthTransition()); + case Property::LineCap: + return makeStyleProperty(getLineCap()); + case Property::LineJoin: + return makeStyleProperty(getLineJoin()); + case Property::LineMiterLimit: + return makeStyleProperty(getLineMiterLimit()); + case Property::LineRoundLimit: + return makeStyleProperty(getLineRoundLimit()); } return {}; } @@ -727,21 +742,8 @@ optional LineLayer::setLayoutProperty(const std::string& name, const Conv if (name == "visibility") { return Layer::setVisibility(value); } - enum class Property { - LineCap, - LineJoin, - LineMiterLimit, - LineRoundLimit, - }; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "line-cap", mbgl::underlying_type(Property::LineCap) }, - { "line-join", mbgl::underlying_type(Property::LineJoin) }, - { "line-miter-limit", mbgl::underlying_type(Property::LineMiterLimit) }, - { "line-round-limit", mbgl::underlying_type(Property::LineRoundLimit) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second <= lastPaintPropertyIndex) { return Error { "layer doesn't support this property" }; } @@ -801,5 +803,3 @@ Mutable LineLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 2e548dfa5b..359e502f3e 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -309,7 +307,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"raster-brightness-max", toUint8(Property::RasterBrightnessMax)}, {"raster-brightness-min", toUint8(Property::RasterBrightnessMin)}, {"raster-contrast", toUint8(Property::RasterContrast)}, @@ -327,11 +325,12 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"raster-resampling-transition", toUint8(Property::RasterResamplingTransition)}, {"raster-saturation-transition", toUint8(Property::RasterSaturationTransition)}}); +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::RasterSaturationTransition); } // namespace optional RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -445,8 +444,8 @@ optional RasterLayer::setPaintProperty(const std::string& name, const Con } StyleProperty RasterLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -501,5 +500,3 @@ Mutable RasterLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 50906c51e2..b3ee0f698c 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Edit scripts/generate-style-code.js, then run `make style-code`. #include @@ -1133,6 +1131,47 @@ enum class Property : uint8_t { TextOpacityTransition, TextTranslateTransition, TextTranslateAnchorTransition, + IconAllowOverlap, + IconAnchor, + IconIgnorePlacement, + IconImage, + IconKeepUpright, + IconOffset, + IconOptional, + IconPadding, + IconPitchAlignment, + IconRotate, + IconRotationAlignment, + IconSize, + IconTextFit, + IconTextFitPadding, + SymbolAvoidEdges, + SymbolPlacement, + SymbolSortKey, + SymbolSpacing, + SymbolZOrder, + TextAllowOverlap, + TextAnchor, + TextField, + TextFont, + TextIgnorePlacement, + TextJustify, + TextKeepUpright, + TextLetterSpacing, + TextLineHeight, + TextMaxAngle, + TextMaxWidth, + TextOffset, + TextOptional, + TextPadding, + TextPitchAlignment, + TextRadialOffset, + TextRotate, + TextRotationAlignment, + TextSize, + TextTransform, + TextVariableAnchor, + TextWritingMode, }; template @@ -1140,7 +1179,7 @@ constexpr uint8_t toUint8(T t) noexcept { return uint8_t(mbgl::underlying_type(t)); } -MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map( +MAPBOX_ETERNAL_CONSTEXPR const auto layerProperties = mapbox::eternal::hash_map( {{"icon-color", toUint8(Property::IconColor)}, {"icon-halo-blur", toUint8(Property::IconHaloBlur)}, {"icon-halo-color", toUint8(Property::IconHaloColor)}, @@ -1168,13 +1207,55 @@ MAPBOX_ETERNAL_CONSTEXPR const auto paintProperties = mapbox::eternal::hash_map< {"text-halo-width-transition", toUint8(Property::TextHaloWidthTransition)}, {"text-opacity-transition", toUint8(Property::TextOpacityTransition)}, {"text-translate-transition", toUint8(Property::TextTranslateTransition)}, - {"text-translate-anchor-transition", toUint8(Property::TextTranslateAnchorTransition)}}); - + {"text-translate-anchor-transition", toUint8(Property::TextTranslateAnchorTransition)}, + {"icon-allow-overlap", toUint8(Property::IconAllowOverlap)}, + {"icon-anchor", toUint8(Property::IconAnchor)}, + {"icon-ignore-placement", toUint8(Property::IconIgnorePlacement)}, + {"icon-image", toUint8(Property::IconImage)}, + {"icon-keep-upright", toUint8(Property::IconKeepUpright)}, + {"icon-offset", toUint8(Property::IconOffset)}, + {"icon-optional", toUint8(Property::IconOptional)}, + {"icon-padding", toUint8(Property::IconPadding)}, + {"icon-pitch-alignment", toUint8(Property::IconPitchAlignment)}, + {"icon-rotate", toUint8(Property::IconRotate)}, + {"icon-rotation-alignment", toUint8(Property::IconRotationAlignment)}, + {"icon-size", toUint8(Property::IconSize)}, + {"icon-text-fit", toUint8(Property::IconTextFit)}, + {"icon-text-fit-padding", toUint8(Property::IconTextFitPadding)}, + {"symbol-avoid-edges", toUint8(Property::SymbolAvoidEdges)}, + {"symbol-placement", toUint8(Property::SymbolPlacement)}, + {"symbol-sort-key", toUint8(Property::SymbolSortKey)}, + {"symbol-spacing", toUint8(Property::SymbolSpacing)}, + {"symbol-z-order", toUint8(Property::SymbolZOrder)}, + {"text-allow-overlap", toUint8(Property::TextAllowOverlap)}, + {"text-anchor", toUint8(Property::TextAnchor)}, + {"text-field", toUint8(Property::TextField)}, + {"text-font", toUint8(Property::TextFont)}, + {"text-ignore-placement", toUint8(Property::TextIgnorePlacement)}, + {"text-justify", toUint8(Property::TextJustify)}, + {"text-keep-upright", toUint8(Property::TextKeepUpright)}, + {"text-letter-spacing", toUint8(Property::TextLetterSpacing)}, + {"text-line-height", toUint8(Property::TextLineHeight)}, + {"text-max-angle", toUint8(Property::TextMaxAngle)}, + {"text-max-width", toUint8(Property::TextMaxWidth)}, + {"text-offset", toUint8(Property::TextOffset)}, + {"text-optional", toUint8(Property::TextOptional)}, + {"text-padding", toUint8(Property::TextPadding)}, + {"text-pitch-alignment", toUint8(Property::TextPitchAlignment)}, + {"text-radial-offset", toUint8(Property::TextRadialOffset)}, + {"text-rotate", toUint8(Property::TextRotate)}, + {"text-rotation-alignment", toUint8(Property::TextRotationAlignment)}, + {"text-size", toUint8(Property::TextSize)}, + {"text-transform", toUint8(Property::TextTransform)}, + {"text-variable-anchor", toUint8(Property::TextVariableAnchor)}, + {"text-writing-mode", toUint8(Property::TextWritingMode)}}); + +constexpr uint8_t lastPaintPropertyIndex = toUint8(Property::TextTranslateAnchorTransition); } // namespace optional SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second > lastPaintPropertyIndex) { return Error{"layer doesn't support this property"}; } @@ -1368,8 +1449,8 @@ optional SymbolLayer::setPaintProperty(const std::string& name, const Con } StyleProperty SymbolLayer::getProperty(const std::string& name) const { - const auto it = paintProperties.find(name.c_str()); - if (it == paintProperties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end()) { return {}; } @@ -1430,6 +1511,88 @@ StyleProperty SymbolLayer::getProperty(const std::string& name) const { return makeStyleProperty(getTextTranslateTransition()); case Property::TextTranslateAnchorTransition: return makeStyleProperty(getTextTranslateAnchorTransition()); + case Property::IconAllowOverlap: + return makeStyleProperty(getIconAllowOverlap()); + case Property::IconAnchor: + return makeStyleProperty(getIconAnchor()); + case Property::IconIgnorePlacement: + return makeStyleProperty(getIconIgnorePlacement()); + case Property::IconImage: + return makeStyleProperty(getIconImage()); + case Property::IconKeepUpright: + return makeStyleProperty(getIconKeepUpright()); + case Property::IconOffset: + return makeStyleProperty(getIconOffset()); + case Property::IconOptional: + return makeStyleProperty(getIconOptional()); + case Property::IconPadding: + return makeStyleProperty(getIconPadding()); + case Property::IconPitchAlignment: + return makeStyleProperty(getIconPitchAlignment()); + case Property::IconRotate: + return makeStyleProperty(getIconRotate()); + case Property::IconRotationAlignment: + return makeStyleProperty(getIconRotationAlignment()); + case Property::IconSize: + return makeStyleProperty(getIconSize()); + case Property::IconTextFit: + return makeStyleProperty(getIconTextFit()); + case Property::IconTextFitPadding: + return makeStyleProperty(getIconTextFitPadding()); + case Property::SymbolAvoidEdges: + return makeStyleProperty(getSymbolAvoidEdges()); + case Property::SymbolPlacement: + return makeStyleProperty(getSymbolPlacement()); + case Property::SymbolSortKey: + return makeStyleProperty(getSymbolSortKey()); + case Property::SymbolSpacing: + return makeStyleProperty(getSymbolSpacing()); + case Property::SymbolZOrder: + return makeStyleProperty(getSymbolZOrder()); + case Property::TextAllowOverlap: + return makeStyleProperty(getTextAllowOverlap()); + case Property::TextAnchor: + return makeStyleProperty(getTextAnchor()); + case Property::TextField: + return makeStyleProperty(getTextField()); + case Property::TextFont: + return makeStyleProperty(getTextFont()); + case Property::TextIgnorePlacement: + return makeStyleProperty(getTextIgnorePlacement()); + case Property::TextJustify: + return makeStyleProperty(getTextJustify()); + case Property::TextKeepUpright: + return makeStyleProperty(getTextKeepUpright()); + case Property::TextLetterSpacing: + return makeStyleProperty(getTextLetterSpacing()); + case Property::TextLineHeight: + return makeStyleProperty(getTextLineHeight()); + case Property::TextMaxAngle: + return makeStyleProperty(getTextMaxAngle()); + case Property::TextMaxWidth: + return makeStyleProperty(getTextMaxWidth()); + case Property::TextOffset: + return makeStyleProperty(getTextOffset()); + case Property::TextOptional: + return makeStyleProperty(getTextOptional()); + case Property::TextPadding: + return makeStyleProperty(getTextPadding()); + case Property::TextPitchAlignment: + return makeStyleProperty(getTextPitchAlignment()); + case Property::TextRadialOffset: + return makeStyleProperty(getTextRadialOffset()); + case Property::TextRotate: + return makeStyleProperty(getTextRotate()); + case Property::TextRotationAlignment: + return makeStyleProperty(getTextRotationAlignment()); + case Property::TextSize: + return makeStyleProperty(getTextSize()); + case Property::TextTransform: + return makeStyleProperty(getTextTransform()); + case Property::TextVariableAnchor: + return makeStyleProperty(getTextVariableAnchor()); + case Property::TextWritingMode: + return makeStyleProperty(getTextWritingMode()); } return {}; } @@ -1438,95 +1601,8 @@ optional SymbolLayer::setLayoutProperty(const std::string& name, const Co if (name == "visibility") { return Layer::setVisibility(value); } - enum class Property { - IconAllowOverlap, - IconAnchor, - IconIgnorePlacement, - IconImage, - IconKeepUpright, - IconOffset, - IconOptional, - IconPadding, - IconPitchAlignment, - IconRotate, - IconRotationAlignment, - IconSize, - IconTextFit, - IconTextFitPadding, - SymbolAvoidEdges, - SymbolPlacement, - SymbolSortKey, - SymbolSpacing, - SymbolZOrder, - TextAllowOverlap, - TextAnchor, - TextField, - TextFont, - TextIgnorePlacement, - TextJustify, - TextKeepUpright, - TextLetterSpacing, - TextLineHeight, - TextMaxAngle, - TextMaxWidth, - TextOffset, - TextOptional, - TextPadding, - TextPitchAlignment, - TextRadialOffset, - TextRotate, - TextRotationAlignment, - TextSize, - TextTransform, - TextVariableAnchor, - TextWritingMode, - }; - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "icon-allow-overlap", mbgl::underlying_type(Property::IconAllowOverlap) }, - { "icon-anchor", mbgl::underlying_type(Property::IconAnchor) }, - { "icon-ignore-placement", mbgl::underlying_type(Property::IconIgnorePlacement) }, - { "icon-image", mbgl::underlying_type(Property::IconImage) }, - { "icon-keep-upright", mbgl::underlying_type(Property::IconKeepUpright) }, - { "icon-offset", mbgl::underlying_type(Property::IconOffset) }, - { "icon-optional", mbgl::underlying_type(Property::IconOptional) }, - { "icon-padding", mbgl::underlying_type(Property::IconPadding) }, - { "icon-pitch-alignment", mbgl::underlying_type(Property::IconPitchAlignment) }, - { "icon-rotate", mbgl::underlying_type(Property::IconRotate) }, - { "icon-rotation-alignment", mbgl::underlying_type(Property::IconRotationAlignment) }, - { "icon-size", mbgl::underlying_type(Property::IconSize) }, - { "icon-text-fit", mbgl::underlying_type(Property::IconTextFit) }, - { "icon-text-fit-padding", mbgl::underlying_type(Property::IconTextFitPadding) }, - { "symbol-avoid-edges", mbgl::underlying_type(Property::SymbolAvoidEdges) }, - { "symbol-placement", mbgl::underlying_type(Property::SymbolPlacement) }, - { "symbol-sort-key", mbgl::underlying_type(Property::SymbolSortKey) }, - { "symbol-spacing", mbgl::underlying_type(Property::SymbolSpacing) }, - { "symbol-z-order", mbgl::underlying_type(Property::SymbolZOrder) }, - { "text-allow-overlap", mbgl::underlying_type(Property::TextAllowOverlap) }, - { "text-anchor", mbgl::underlying_type(Property::TextAnchor) }, - { "text-field", mbgl::underlying_type(Property::TextField) }, - { "text-font", mbgl::underlying_type(Property::TextFont) }, - { "text-ignore-placement", mbgl::underlying_type(Property::TextIgnorePlacement) }, - { "text-justify", mbgl::underlying_type(Property::TextJustify) }, - { "text-keep-upright", mbgl::underlying_type(Property::TextKeepUpright) }, - { "text-letter-spacing", mbgl::underlying_type(Property::TextLetterSpacing) }, - { "text-line-height", mbgl::underlying_type(Property::TextLineHeight) }, - { "text-max-angle", mbgl::underlying_type(Property::TextMaxAngle) }, - { "text-max-width", mbgl::underlying_type(Property::TextMaxWidth) }, - { "text-offset", mbgl::underlying_type(Property::TextOffset) }, - { "text-optional", mbgl::underlying_type(Property::TextOptional) }, - { "text-padding", mbgl::underlying_type(Property::TextPadding) }, - { "text-pitch-alignment", mbgl::underlying_type(Property::TextPitchAlignment) }, - { "text-radial-offset", mbgl::underlying_type(Property::TextRadialOffset) }, - { "text-rotate", mbgl::underlying_type(Property::TextRotate) }, - { "text-rotation-alignment", mbgl::underlying_type(Property::TextRotationAlignment) }, - { "text-size", mbgl::underlying_type(Property::TextSize) }, - { "text-transform", mbgl::underlying_type(Property::TextTransform) }, - { "text-variable-anchor", mbgl::underlying_type(Property::TextVariableAnchor) }, - { "text-writing-mode", mbgl::underlying_type(Property::TextWritingMode) } - }); - - const auto it = properties.find(name.c_str()); - if (it == properties.end()) { + const auto it = layerProperties.find(name.c_str()); + if (it == layerProperties.end() || it->second <= lastPaintPropertyIndex) { return Error { "layer doesn't support this property" }; } @@ -1879,5 +1955,3 @@ Mutable SymbolLayer::mutableBaseImpl() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 7293c1c6ca..5872f4ecd5 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -946,6 +946,9 @@ TEST(Map, UniversalStyleGetter) { "line-color": "red", "line-opacity": 0.5, "line-width": ["get", "width"] + }, + "layout": { + "line-cap": "butt" } }] })STYLE"); @@ -999,4 +1002,10 @@ TEST(Map, UniversalStyleGetter) { EXPECT_EQ("get", *operation[0].getString()); ASSERT_TRUE(operation[1].getString()); EXPECT_EQ("width", *operation[1].getString()); + + StyleProperty lineCap = lineLayer->getProperty("line-cap"); + ASSERT_TRUE(lineCap.value); + EXPECT_EQ(StyleProperty::Kind::Constant, lineCap.kind); + ASSERT_TRUE(lineCap.value.getInt()); + EXPECT_EQ(mbgl::underlying_type(mbgl::style::LineCapType::Butt), *lineCap.value.getInt()); } \ No newline at end of file -- cgit v1.2.1 From d90b2bb6dc2a19961e029963e591d702f70dd721 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 26 Sep 2019 18:26:11 +0300 Subject: [core] Introduce Light::getProperty() --- include/mbgl/style/conversion_impl.hpp | 7 +++ include/mbgl/style/light.hpp | 2 + include/mbgl/style/light.hpp.ejs | 2 + src/mbgl/style/light.cpp | 83 +++++++++++++++++++++++----------- src/mbgl/style/light.cpp.ejs | 49 ++++++++++++++------ 5 files changed, 104 insertions(+), 39 deletions(-) diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 7abe7bf923..3e4236949e 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -342,6 +342,13 @@ struct ValueFactory::value>::t } }; +template <> +struct ValueFactory { + static Value make(const Position& position) { + return ValueFactory>::make(position.getSpherical()); + } +}; + template Value makeValue(T&& arg) { return ValueFactory>::make(std::forward(arg)); diff --git a/include/mbgl/style/light.hpp b/include/mbgl/style/light.hpp index 9a82eb14b5..7434fb2882 100644 --- a/include/mbgl/style/light.hpp +++ b/include/mbgl/style/light.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -22,6 +23,7 @@ public: // Dynamic properties optional setProperty(const std::string& name, const conversion::Convertible& value); + StyleProperty getProperty(const std::string&) const; static LightAnchorType getDefaultAnchor(); PropertyValue getAnchor() const; diff --git a/include/mbgl/style/light.hpp.ejs b/include/mbgl/style/light.hpp.ejs index a5b907b4dc..e4661dc59b 100644 --- a/include/mbgl/style/light.hpp.ejs +++ b/include/mbgl/style/light.hpp.ejs @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -25,6 +26,7 @@ public: // Dynamic properties optional setProperty(const std::string& name, const conversion::Convertible& value); + StyleProperty getProperty(const std::string&) const; <% for (const property of properties) { -%> static <%- evaluatedType(property) %> getDefault<%- camelize(property.name) %>(); diff --git a/src/mbgl/style/light.cpp b/src/mbgl/style/light.cpp index be56a0d93b..a10e693073 100644 --- a/src/mbgl/style/light.cpp +++ b/src/mbgl/style/light.cpp @@ -1,5 +1,3 @@ -// clang-format off - // This file is generated. Do not edit. #include @@ -36,29 +34,37 @@ Mutable Light::mutableImpl() const { using namespace conversion; -optional Light::setProperty(const std::string& name, const Convertible& value) { - enum class Property { - Anchor, - Color, - Intensity, - Position, - AnchorTransition, - ColorTransition, - IntensityTransition, - PositionTransition, - }; - - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - { "anchor", mbgl::underlying_type(Property::Anchor) }, - { "color", mbgl::underlying_type(Property::Color) }, - { "intensity", mbgl::underlying_type(Property::Intensity) }, - { "position", mbgl::underlying_type(Property::Position) }, - { "anchor-transition", mbgl::underlying_type(Property::AnchorTransition) }, - { "color-transition", mbgl::underlying_type(Property::ColorTransition) }, - { "intensity-transition", mbgl::underlying_type(Property::IntensityTransition) }, - { "position-transition", mbgl::underlying_type(Property::PositionTransition) } - }); +namespace { + +enum class Property : uint8_t { + Anchor, + Color, + Intensity, + Position, + AnchorTransition, + ColorTransition, + IntensityTransition, + PositionTransition, +}; + +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} + +MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map( + {{"anchor", toUint8(Property::Anchor)}, + {"color", toUint8(Property::Color)}, + {"intensity", toUint8(Property::Intensity)}, + {"position", toUint8(Property::Position)}, + {"anchor-transition", toUint8(Property::AnchorTransition)}, + {"color-transition", toUint8(Property::ColorTransition)}, + {"intensity-transition", toUint8(Property::IntensityTransition)}, + {"position-transition", toUint8(Property::PositionTransition)}}); +} // namespace + +optional Light::setProperty(const std::string& name, const Convertible& value) { const auto it = properties.find(name.c_str()); if (it == properties.end()) { return Error { "light doesn't support this property" }; @@ -146,6 +152,33 @@ optional Light::setProperty(const std::string& name, const Convertible& v return Error { "light doesn't support this property" }; } +StyleProperty Light::getProperty(const std::string& name) const { + const auto it = properties.find(name.c_str()); + if (it == properties.end()) { + return {}; + } + + switch (static_cast(it->second)) { + case Property::Anchor: + return makeStyleProperty(getAnchor()); + case Property::Color: + return makeStyleProperty(getColor()); + case Property::Intensity: + return makeStyleProperty(getIntensity()); + case Property::Position: + return makeStyleProperty(getPosition()); + case Property::AnchorTransition: + return makeStyleProperty(getAnchorTransition()); + case Property::ColorTransition: + return makeStyleProperty(getColorTransition()); + case Property::IntensityTransition: + return makeStyleProperty(getIntensityTransition()); + case Property::PositionTransition: + return makeStyleProperty(getPositionTransition()); + } + return {}; +} + LightAnchorType Light::getDefaultAnchor() { return LightAnchor::defaultValue(); } @@ -253,5 +286,3 @@ TransitionOptions Light::getPositionTransition() const { } // namespace style } // namespace mbgl - -// clang-format on diff --git a/src/mbgl/style/light.cpp.ejs b/src/mbgl/style/light.cpp.ejs index 55cc013827..68c1bf59e2 100644 --- a/src/mbgl/style/light.cpp.ejs +++ b/src/mbgl/style/light.cpp.ejs @@ -1,8 +1,6 @@ <% const properties = locals.properties; -%> -// clang-format off - // This file is generated. Do not edit. #include @@ -39,21 +37,29 @@ Mutable Light::mutableImpl() const { using namespace conversion; -optional Light::setProperty(const std::string& name, const Convertible& value) { - enum class Property { +namespace { + +enum class Property : uint8_t { <% for (const property of properties) { -%> - <%- camelize(property.name) %>, + <%- camelize(property.name) %>, <% } -%> <% for (const property of properties) { -%> - <%- camelize(property.name) %>Transition, + <%- camelize(property.name) %>Transition, <% } -%> - }; +}; + +template +constexpr uint8_t toUint8(T t) noexcept { + return uint8_t(mbgl::underlying_type(t)); +} - MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map({ - <%- properties.map(p => `{ "${p.name}", mbgl::underlying_type(Property::${camelize(p.name)}) }`).join(',\n ') %>, - <%- properties.map(p => `{ "${p.name}-transition", mbgl::underlying_type(Property::${camelize(p.name)}Transition) }`).join(',\n ') %> - }); +MAPBOX_ETERNAL_CONSTEXPR const auto properties = mapbox::eternal::hash_map( + {<%- properties.map(p => `{"${p.name}", toUint8(Property::${camelize(p.name)})}`).join(',\n ') %>, + <%- properties.map(p => `{"${p.name}-transition", toUint8(Property::${camelize(p.name)}Transition)}`).join(',\n ') %>}); +} // namespace + +optional Light::setProperty(const std::string& name, const Convertible& value) { const auto it = properties.find(name.c_str()); if (it == properties.end()) { return Error { "light doesn't support this property" }; @@ -107,6 +113,25 @@ optional Light::setProperty(const std::string& name, const Convertible& v return Error { "light doesn't support this property" }; } +StyleProperty Light::getProperty(const std::string& name) const { + const auto it = properties.find(name.c_str()); + if (it == properties.end()) { + return {}; + } + + switch (static_cast(it->second)) { +<% for (const property of properties) { -%> + case Property::<%- camelize(property.name) %>: + return makeStyleProperty(get<%- camelize(property.name) %>()); +<% } -%> +<% for (const property of properties) { -%> + case Property::<%- camelize(property.name) %>Transition: + return makeStyleProperty(get<%- camelize(property.name) %>Transition()); +<% } -%> + } + return {}; +} + <% for (const property of properties) { -%> <%- evaluatedType(property) %> Light::getDefault<%- camelize(property.name) %>() { return Light<%- camelize(property.name) %>::defaultValue(); @@ -138,5 +163,3 @@ TransitionOptions Light::get<%- camelize(property.name) %>Transition() const { } // namespace style } // namespace mbgl - -// clang-format on -- cgit v1.2.1 From bb9b1ab62438f733ad278cb03f781116b9f3d721 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 27 Sep 2019 15:39:21 +0300 Subject: [core] Return enum layer property values as string The output of Layer::getProperty is a mapbox::base::Value which is equivalent to JSON. When setting the value of an enum property via JSON its value would be a string, so it would be natural to return a string too. Also, the numbers generated depend on the enum definition. They are not part of the style spec. --- include/mbgl/style/conversion_impl.hpp | 2 +- test/map/map.test.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp index 3e4236949e..3e1b8455e5 100644 --- a/include/mbgl/style/conversion_impl.hpp +++ b/include/mbgl/style/conversion_impl.hpp @@ -327,7 +327,7 @@ struct ValueFactory::value && !is_l template struct ValueFactory::value>::type> { - static Value make(T arg) { return {int64_t(arg)}; } + static Value make(T arg) { return {Enum::toString(arg)}; } }; template diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 5872f4ecd5..6f0f126d3d 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -1006,6 +1006,6 @@ TEST(Map, UniversalStyleGetter) { StyleProperty lineCap = lineLayer->getProperty("line-cap"); ASSERT_TRUE(lineCap.value); EXPECT_EQ(StyleProperty::Kind::Constant, lineCap.kind); - ASSERT_TRUE(lineCap.value.getInt()); - EXPECT_EQ(mbgl::underlying_type(mbgl::style::LineCapType::Butt), *lineCap.value.getInt()); -} \ No newline at end of file + ASSERT_TRUE(lineCap.value.getString()); + EXPECT_EQ(std::string("butt"), *lineCap.value.getString()); +} -- cgit v1.2.1 From d446b3382b7de03d9031445e37c1ebf183092ea2 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 27 Sep 2019 18:22:57 +0300 Subject: [core] Enable move semantics for StyleProperty --- include/mbgl/style/style_property.hpp | 12 ++++++--- test/map/map.test.cpp | 48 +++++++++++++++++------------------ 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/include/mbgl/style/style_property.hpp b/include/mbgl/style/style_property.hpp index 43787c7919..fc34078dec 100644 --- a/include/mbgl/style/style_property.hpp +++ b/include/mbgl/style/style_property.hpp @@ -8,12 +8,18 @@ namespace style { /** * @brief Generic representation of a style property. */ -struct StyleProperty { +class StyleProperty { +public: enum class Kind : uint8_t { Undefined, Constant, Expression, Transition }; StyleProperty(Value value_, Kind kind_) : value(std::move(value_)), kind(kind_) {} StyleProperty() = default; - const Value value; - const Kind kind = Kind::Undefined; + const Value& getValue() const { return value; } + Value& getValue() { return value; } + Kind getKind() const { return kind; } + +private: + Value value; + Kind kind = Kind::Undefined; }; } // namespace style diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 6f0f126d3d..3f3145059a 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -957,41 +957,41 @@ TEST(Map, UniversalStyleGetter) { ASSERT_TRUE(lineLayer); StyleProperty nonexistent = lineLayer->getProperty("nonexistent"); - ASSERT_FALSE(nonexistent.value); - EXPECT_EQ(StyleProperty::Kind::Undefined, nonexistent.kind); + ASSERT_FALSE(nonexistent.getValue()); + EXPECT_EQ(StyleProperty::Kind::Undefined, nonexistent.getKind()); StyleProperty undefined = lineLayer->getProperty("line-blur"); - ASSERT_FALSE(undefined.value); - EXPECT_EQ(StyleProperty::Kind::Undefined, undefined.kind); + ASSERT_FALSE(undefined.getValue()); + EXPECT_EQ(StyleProperty::Kind::Undefined, undefined.getKind()); StyleProperty lineColor = lineLayer->getProperty("line-color"); - ASSERT_TRUE(lineColor.value); - EXPECT_EQ(StyleProperty::Kind::Constant, lineColor.kind); - ASSERT_TRUE(lineColor.value.getObject()); - const auto& color = *(lineColor.value.getObject()); + ASSERT_TRUE(lineColor.getValue()); + EXPECT_EQ(StyleProperty::Kind::Constant, lineColor.getKind()); + ASSERT_TRUE(lineColor.getValue().getObject()); + const auto& color = *(lineColor.getValue().getObject()); EXPECT_EQ(1.0, *color.at("r").getDouble()); EXPECT_EQ(0.0, *color.at("g").getDouble()); EXPECT_EQ(0.0, *color.at("b").getDouble()); EXPECT_EQ(1.0, *color.at("a").getDouble()); StyleProperty lineOpacity = lineLayer->getProperty("line-opacity"); - ASSERT_TRUE(lineOpacity.value); - EXPECT_EQ(StyleProperty::Kind::Constant, lineOpacity.kind); - ASSERT_TRUE(lineOpacity.value.getDouble()); - EXPECT_EQ(0.5, *lineOpacity.value.getDouble()); + ASSERT_TRUE(lineOpacity.getValue()); + EXPECT_EQ(StyleProperty::Kind::Constant, lineOpacity.getKind()); + ASSERT_TRUE(lineOpacity.getValue().getDouble()); + EXPECT_EQ(0.5, *lineOpacity.getValue().getDouble()); StyleProperty lineOpacityTransition = lineLayer->getProperty("line-opacity-transition"); - ASSERT_TRUE(lineOpacityTransition.value); - EXPECT_EQ(StyleProperty::Kind::Transition, lineOpacityTransition.kind); - ASSERT_TRUE(lineOpacityTransition.value.getArray()); - EXPECT_EQ(3u, lineOpacityTransition.value.getArray()->size()); + ASSERT_TRUE(lineOpacityTransition.getValue()); + EXPECT_EQ(StyleProperty::Kind::Transition, lineOpacityTransition.getKind()); + ASSERT_TRUE(lineOpacityTransition.getValue().getArray()); + EXPECT_EQ(3u, lineOpacityTransition.getValue().getArray()->size()); StyleProperty lineWidth = lineLayer->getProperty("line-width"); - ASSERT_TRUE(lineWidth.value); - EXPECT_EQ(StyleProperty::Kind::Expression, lineWidth.kind); - ASSERT_TRUE(lineWidth.value.getArray()); + ASSERT_TRUE(lineWidth.getValue()); + EXPECT_EQ(StyleProperty::Kind::Expression, lineWidth.getKind()); + ASSERT_TRUE(lineWidth.getValue().getArray()); - const auto& expression = *lineWidth.value.getArray(); + const auto& expression = *lineWidth.getValue().getArray(); EXPECT_EQ(2u, expression.size()); ASSERT_TRUE(expression[0].getString()); EXPECT_EQ("number", *expression[0].getString()); @@ -1004,8 +1004,8 @@ TEST(Map, UniversalStyleGetter) { EXPECT_EQ("width", *operation[1].getString()); StyleProperty lineCap = lineLayer->getProperty("line-cap"); - ASSERT_TRUE(lineCap.value); - EXPECT_EQ(StyleProperty::Kind::Constant, lineCap.kind); - ASSERT_TRUE(lineCap.value.getString()); - EXPECT_EQ(std::string("butt"), *lineCap.value.getString()); + ASSERT_TRUE(lineCap.getValue()); + EXPECT_EQ(StyleProperty::Kind::Constant, lineCap.getKind()); + ASSERT_TRUE(lineCap.getValue().getString()); + EXPECT_EQ(std::string("butt"), *lineCap.getValue().getString()); } -- cgit v1.2.1 From b0f3875be269c8523381e72c3abc79ce3a598cf6 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 1 Oct 2019 01:02:16 +0900 Subject: [docs] Correct license typo in README (#15707) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 392e41ac51..d125fc53c8 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,6 @@ This repository hosts the cross-platform Mapbox GL Native library, plus convenie ## License -Mapbox GL Native is licensed under the [3-Clause BSD license](LICENSE.md). The licenses of its dependencies are tracked via [FOSSA](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fmapbox-gl-native): +Mapbox GL Native is licensed under the [2-Clause BSD license](LICENSE.md). The licenses of its dependencies are tracked via [FOSSA](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fmapbox-gl-native): [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fmapbox-gl-native.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fmapbox-gl-native) -- cgit v1.2.1 From 6965fc310042dd6afd07e03baf9aff67d0f97ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 19 Sep 2019 09:28:58 +0200 Subject: [android] - changelog for v8.3.2 --- platform/android/CHANGELOG.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index f0c5b2ff91..e42082fd2f 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -25,11 +25,18 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Fixed MapSnapshotter so that `MapSnapshotter.withApiBaseUri` works again. [#15642](https://github.com/mapbox/mapbox-gl-native/pull/15642) - Fixed an assertion hit caused by possibility of adding a layer to an incompatible source. [#15644](https://github.com/mapbox/mapbox-gl-native/pull/15644) +## 8.3.2 - September 19, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.1...android-v8.3.2) since [Mapbox Maps SDK for Android v8.3.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.1): + +### Bug fixes + - Fixed an issue of integer overflow when converting `tileCoordinates` to `LatLon`, which caused issues such as `queryRenderedFeatures` and `querySourceFeatures` returning incorrect coordinates at zoom levels 20 and higher. [#15560](https://github.com/mapbox/mapbox-gl-native/pull/15560) + ## 8.3.1 - September 18, 2019 -[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.3.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0): +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0...android-v8.3.1) since [Mapbox Maps SDK for Android v8.3.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0): ### Bug fixes - Updated earcut.hpp submodule file [#15660](https://github.com/mapbox/mapbox-gl-native/pull/15660) + - Fixed a wrong variable assignment of `MapSnapshotter.Options.withApiBaseUri`. [#15642](https://github.com/mapbox/mapbox-gl-native/pull/15642) ## 8.4.0-alpha.2 - September 11, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-alpha.1...android-v8.4.0-alpha.2) since [Mapbox Maps SDK for Android v8.4.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-alpha.1): -- cgit v1.2.1 From ff6a3ee5b7fea7f4c18fed3480308c34fd434ed6 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 2 Oct 2019 12:54:30 +0300 Subject: [core] Suppress network requests for invisible tiles If the render source does not need rendering, we set necessity for its tiles to `optional`, and thus suppress network requests on tiles expiration. --- src/mbgl/renderer/tile_pyramid.cpp | 4 ++ test/style/source.test.cpp | 76 +++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 2bf6e2e1a9..586d3b5a8a 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -68,6 +68,10 @@ void TilePyramid::update(const std::vector>& l if (!needsRendering) { if (!needsRelayout) { for (auto& entry : tiles) { + // These tiles are invisible, we set optional necessity + // for them and thus suppress network requests on + // tiles expiration (see `OnlineFileRequest`). + entry.second->setNecessity(TileNecessity::Optional); cache.add(entry.first, std::move(entry.second)); } } diff --git a/test/style/source.test.cpp b/test/style/source.test.cpp index ca0e79f46a..a08d11c7ad 100644 --- a/test/style/source.test.cpp +++ b/test/style/source.test.cpp @@ -35,10 +35,11 @@ #include #include -#include #include #include +#include #include +#include #include #include @@ -793,6 +794,79 @@ TEST(Source, CustomGeometrySourceSetTileData) { test.run(); } +namespace { + +class FakeTileSource; + +class FakeTile : public Tile { +public: + FakeTile(FakeTileSource& source_, const OverscaledTileID& tileID) + : Tile(Tile::Kind::Geometry, tileID), source(source_) { + renderable = true; + } + void setNecessity(TileNecessity necessity) override; + bool layerPropertiesUpdated(const Immutable&) override { return true; } + + std::unique_ptr createRenderData() override { return nullptr; } + +private: + FakeTileSource& source; +}; + +class FakeTileSource : public RenderTileSetSource { +public: + MOCK_METHOD1(tileSetNecessity, void(TileNecessity)); + + explicit FakeTileSource(Immutable impl_) : RenderTileSetSource(std::move(impl_)) {} + void updateInternal(const Tileset& tileset, + const std::vector>& layers, + const bool needsRendering, + const bool needsRelayout, + const TileParameters& parameters) override { + tilePyramid.update(layers, + needsRendering, + needsRelayout, + parameters, + SourceType::Vector, + util::tileSize, + tileset.zoomRange, + tileset.bounds, + [&](const OverscaledTileID& tileID) { return std::make_unique(*this, tileID); }); + } + + const optional& getTileset() const override { + return static_cast(*baseImpl).tileset; + } +}; + +void FakeTile::setNecessity(TileNecessity necessity) { + source.tileSetNecessity(necessity); +} + +} // namespace + +TEST(Source, InvisibleSourcesTileNecessity) { + SourceTest test; + VectorSource initialized("source", Tileset{{"tiles"}}); + initialized.loadDescription(*test.fileSource); + + FakeTileSource renderTilesetSource{initialized.baseImpl}; + RenderSource* renderSource = &renderTilesetSource; + LineLayer layer("id", "source"); + Immutable layerProperties = + makeMutable(staticImmutableCast(layer.baseImpl)); + std::vector> layers{layerProperties}; + EXPECT_CALL(renderTilesetSource, tileSetNecessity(TileNecessity::Required)).Times(1); + renderSource->update(initialized.baseImpl, layers, true, true, test.tileParameters); + + // Necessity for invisible tiles must be set to `optional`. + EXPECT_CALL(renderTilesetSource, tileSetNecessity(TileNecessity::Optional)).Times(1); + renderSource->update(initialized.baseImpl, layers, false, false, test.tileParameters); + + // Necessity is again `required` once tiles get back visible. + EXPECT_CALL(renderTilesetSource, tileSetNecessity(TileNecessity::Required)).Times(1); + renderSource->update(initialized.baseImpl, layers, true, false, test.tileParameters); +} TEST(Source, RenderTileSetSourceUpdate) { SourceTest test; -- cgit v1.2.1 From b2a834228178461723a7840072f526b3d84da7b7 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 2 Oct 2019 16:29:33 +0300 Subject: Exclude Source.InvisibleSourcesTileNecessity from sanitizer CI --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 66ebaf0226..081ab9a3bd 100644 --- a/circle.yml +++ b/circle.yml @@ -619,8 +619,8 @@ commands: - run: name: Run tests command: | - # Source.RenderTileSetSourceUpdate is filtered out due to #15294 - xvfb-run --server-args="-screen 0 1024x768x24" make run-test--Source.RenderTileSetSourceUpdate 2> >(tee sanitizer 1>&2) + # Source.RenderTileSetSourceUpdate and Source.InvisibleSourcesTileNecessity are filtered out due to #15294 + xvfb-run --server-args="-screen 0 1024x768x24" make run-test--Source.RenderTileSetSourceUpdate:Source.InvisibleSourcesTileNecessity 2> >(tee sanitizer 1>&2) # Unfortunately, Google Test eats the status code, so we'll have to check the output. [ -z "$(sed -n '/^SUMMARY: .*Sanitizer:/p' sanitizer)" ] -- cgit v1.2.1 From 90b37927eb67be18c60b05336730d9ea419d8b5e Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 2 Oct 2019 19:03:00 +0300 Subject: [ios][android] Add change log entry --- platform/android/CHANGELOG.md | 3 +++ platform/ios/CHANGELOG.md | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index e42082fd2f..14a68537c2 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,6 +4,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master +### Bug fixes + - Suppress network requests for expired tiles update, if these tiles are invisible. [#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741) + ## 8.4.0 - September 25, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index a326161595..b7caf0485a 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. +## master + +### Other changes + +* Suppress network requests for expired tiles update, if these tiles are invisible. ([#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741)) + ## 5.4.0 - September 25, 2019 ### Styles and rendering -- cgit v1.2.1 From dfca8fb2149eea69e7cff08a15d964b4a5e4d710 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Wed, 2 Oct 2019 13:49:33 -0400 Subject: [core] fix opacity interpolation for composition expressions (#15738) port https://github.com/mapbox/mapbox-gl-js/pull/8818 --- platform/node/test/ignores.json | 1 + src/mbgl/renderer/paint_property_binder.hpp | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json index f053b2add1..8da2905dbb 100644 --- a/platform/node/test/ignores.json +++ b/platform/node/test/ignores.json @@ -71,6 +71,7 @@ "render-tests/circle-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008", "render-tests/fill-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008", "render-tests/line-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008", + "render-tests/regressions/mapbox-gl-js#8817": "skip - https://github.com/mapbox/mapbox-gl-native/issues/15737", "query-tests/fill-extrusion/base-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139", "query-tests/fill-extrusion/box-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139", "query-tests/fill-extrusion/side-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139", diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 1a36f8a2e5..db9f61411a 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -370,11 +370,10 @@ public: } std::tuple interpolationFactor(float currentZoom) const override { - if (expression.useIntegerZoom) { - return std::tuple { expression.interpolationFactor(zoomRange, std::floor(currentZoom)) }; - } else { - return std::tuple { expression.interpolationFactor(zoomRange, currentZoom) }; - } + const float possiblyRoundedZoom = expression.useIntegerZoom ? std::floor(currentZoom) : currentZoom; + + return std::tuple{ + ::fmax(0.0, ::fmin(1.0, expression.interpolationFactor(zoomRange, possiblyRoundedZoom)))}; } std::tuple uniformValue(const PossiblyEvaluatedPropertyValue& currentValue) const override { -- cgit v1.2.1 From daf8e1289c3c8b437c97e1ec4250b521fa6edc52 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Wed, 2 Oct 2019 12:59:09 -0700 Subject: [ios] Podspec & changelog updates for v5.5.0-alpha.1 --- platform/ios/CHANGELOG.md | 2 +- platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec | 2 +- platform/ios/Mapbox-iOS-SDK-stripped.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index b7caf0485a..d8d242e5ea 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,7 +2,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. -## master +## 5.5.0 ### Other changes diff --git a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec index 68c45dd399..9d01fb63b3 100644 --- a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec +++ b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '5.4.0' + version = '5.5.0-alpha.1' m.name = 'Mapbox-iOS-SDK-snapshot-dynamic' m.version = "#{version}-snapshot" diff --git a/platform/ios/Mapbox-iOS-SDK-stripped.podspec b/platform/ios/Mapbox-iOS-SDK-stripped.podspec index 225ef2729b..ff5e503d96 100644 --- a/platform/ios/Mapbox-iOS-SDK-stripped.podspec +++ b/platform/ios/Mapbox-iOS-SDK-stripped.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '5.4.0' + version = '5.5.0-alpha.1' m.name = 'Mapbox-iOS-SDK-stripped' m.version = "#{version}-stripped" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index f5d8a45d4e..44d3ee70a9 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 = '5.4.0' + version = '5.5.0-alpha.1' m.name = 'Mapbox-iOS-SDK' m.version = version -- cgit v1.2.1 From 747524778273b483af9f7b247d0756b524b82b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 2 Oct 2019 13:15:26 +0200 Subject: [android] - remove projected meters per pixel and pixel ratio relation The projected meters per pixel calculation is not dependent on the pixel ratio but rather the tile size, therefore, the division when fetching the value is not necessary. --- .../src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java | 2 +- .../src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 8496160c7e..c844133f41 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 @@ -620,7 +620,7 @@ final class NativeMapView implements NativeMap { if (checkState("getMetersPerPixelAtLatitude")) { return 0; } - return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio; + return nativeGetMetersPerPixelAtLatitude(lat, getZoom()); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt index b13bb6b796..9117271292 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt @@ -254,7 +254,7 @@ class NativeMapViewTest : AppCenter() { @Test @UiThreadTest fun testGetProjectedMetersAtLatitude() { - val expected = 38986.83510557766 + val expected = 77973.67021115532 val actual = nativeMapView.getMetersPerPixelAtLatitude(5.0) assertEquals("Get projected meters should match", expected, actual) } -- cgit v1.2.1 From 10c14bee45dc9c91cee8fe634fe150c361d0937a Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Thu, 3 Oct 2019 17:00:27 +0300 Subject: [android] - changelog for 8.5.0-alpha.1 (#15753) * [android] Update changelog for v8.5.0-alpha.1 --- platform/android/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 14a68537c2..e28b5849e7 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,8 +4,12 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master +## 8.5.0-alpha.1 - October 3, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0...android-v8.5.0-alpha.1) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0): ### Bug fixes - Suppress network requests for expired tiles update, if these tiles are invisible. [#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741) + - Fixed opacity interpolation for composition expressions [#15738](https://github.com/mapbox/mapbox-gl-native/pull/15738) + - Fixed an issue where `Projection#getMetersPerPixelAtLatitude` returned a value incorrectly divided by the pixel ratio. This also fixes an issue where `LocationComponent` accuracy circle's radius was artificially increased. [#15742](https://github.com/mapbox/mapbox-gl-native/pull/15742) ## 8.4.0 - September 25, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): -- cgit v1.2.1 From 4b4e82864783a28c0785ebbf2edea84a722d46ae Mon Sep 17 00:00:00 2001 From: Jordan Kiley Date: Thu, 3 Oct 2019 11:07:41 -0700 Subject: [ios] Disable iOS code coverage script #15749 --- circle.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 081ab9a3bd..4210620935 100644 --- a/circle.yml +++ b/circle.yml @@ -1317,7 +1317,10 @@ jobs: - run: name: Get iOS code coverage command: | - platform/ios/scripts/ios-code-coverage.sh CI + echo "Skipping iOS code coverage" + # Currently failing, need to update for Xcode 11 + # platform/ios/scripts/ios-code-coverage.sh CI + # - save-dependencies - collect-xcode-build-logs - upload-xcode-build-logs -- cgit v1.2.1 From ac1868882470cb3b2549c65f13cd35efb8105b74 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 2 Oct 2019 17:50:30 +0300 Subject: [core][benchmark] Add API_renderStill_multiple_sources benchmark --- benchmark/api/render.benchmark.cpp | 44 ++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/benchmark/api/render.benchmark.cpp b/benchmark/api/render.benchmark.cpp index 305ae8ce79..f192e7d3a3 100644 --- a/benchmark/api/render.benchmark.cpp +++ b/benchmark/api/render.benchmark.cpp @@ -1,18 +1,22 @@ #include +#include #include #include #include -#include #include -#include -#include -#include #include +#include +#include +#include +#include +#include #include #include #include +#include + using namespace mbgl; namespace { @@ -94,7 +98,39 @@ static void API_renderStill_recreate_map(::benchmark::State& state) { } } +static void API_renderStill_multiple_sources(::benchmark::State& state) { + using namespace mbgl::style; + RenderBenchmark bench; + HeadlessFrontend frontend{size, pixelRatio}; + Map map{frontend, + MapObserver::nullObserver(), + MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), + ResourceOptions().withCachePath(cachePath).withAccessToken("foobar")}; + prepare(map); + auto& style = map.getStyle(); + const int kSourcesCount = 50; + const int kLayersCount = 50; + for (int i = 0; i < kSourcesCount; ++i) { + std::ostringstream sourceOss; + sourceOss << "GeoJSONSource" << i; + std::string sourceId{sourceOss.str()}; + auto source = std::make_unique(sourceId); + style.addSource(std::move(source)); + for (int j = 0; j < kLayersCount; ++j) { + std::ostringstream layerOss; + layerOss << sourceId << '#' << j; + auto layer = std::make_unique(layerOss.str(), sourceId); + style.addLayer(std::move(layer)); + } + } + + while (state.KeepRunning()) { + frontend.render(map); + } +} + BENCHMARK(API_renderStill_reuse_map); BENCHMARK(API_renderStill_reuse_map_formatted_labels); BENCHMARK(API_renderStill_reuse_map_switch_styles); BENCHMARK(API_renderStill_recreate_map); +BENCHMARK(API_renderStill_multiple_sources); -- cgit v1.2.1 From 064c60cdcab331bc19fe399492179dcb5b29121a Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 3 Oct 2019 18:32:07 +0300 Subject: [core] Orchestration performance for styles with multiple sources RenderOrchestrator holds a vector of ordered rendered layers, in order to minimize calling of `getRenderLayer()`, which could be quite expensive as it calculates hash of the layer Id. This change improves orchestration performance in particular for the styles that have multiple sources. The `API_renderStill_multiple_sources` benchmark runs approximately 70% faster with the changes applied. --- src/mbgl/renderer/render_orchestrator.cpp | 61 ++++++++++++++++++------------- src/mbgl/renderer/render_orchestrator.hpp | 4 +- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 28f6ab3199..50077784b5 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -220,6 +220,7 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar const LayerDifference layerDiff = diffLayers(layerImpls, updateParameters.layers); layerImpls = updateParameters.layers; + const bool layersAddedOrRemoved = !layerDiff.added.empty() || !layerDiff.removed.empty(); // Remove render layers for removed layers. for (const auto& entry : layerDiff.removed) { @@ -238,20 +239,31 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar renderLayers.at(entry.first)->transition(transitionParameters, entry.second.after); } - if (!layerDiff.removed.empty() || !layerDiff.added.empty() || !layerDiff.changed.empty()) { - glyphManager->evict(fontStacks(*updateParameters.layers)); + if (layersAddedOrRemoved) { + orderedLayers.clear(); + orderedLayers.reserve(layerImpls->size()); + for (const auto& layerImpl : *layerImpls) { + RenderLayer* layer = renderLayers.at(layerImpl->id).get(); + assert(layer); + orderedLayers.emplace_back(*layer); + } + } + assert(orderedLayers.size() == renderLayers.size()); + + if (layersAddedOrRemoved || !layerDiff.changed.empty()) { + glyphManager->evict(fontStacks(*layerImpls)); } // Update layers for class and zoom changes. std::unordered_set constantsMaskChanged; - for (const auto& entry : renderLayers) { - RenderLayer& layer = *entry.second; - const bool layerAddedOrChanged = layerDiff.added.count(entry.first) || layerDiff.changed.count(entry.first); + for (RenderLayer& layer : orderedLayers) { + const std::string& id = layer.getID(); + const bool layerAddedOrChanged = layerDiff.added.count(id) || layerDiff.changed.count(id); if (layerAddedOrChanged || zoomChanged || layer.hasTransition() || layer.hasCrossfade()) { auto previousMask = layer.evaluatedProperties->constantsMask(); layer.evaluate(evaluationParameters); if (previousMask != layer.evaluatedProperties->constantsMask()) { - constantsMaskChanged.insert(layer.getID()); + constantsMaskChanged.insert(id); } } } @@ -281,7 +293,7 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar renderLight.getEvaluated()); std::set layerRenderItems; - std::vector> layersNeedPlacement; + layersNeedPlacement.clear(); auto renderItemsEmplaceHint = layerRenderItems.begin(); // Reserve size for filteredLayersForSource if there are sources. @@ -293,27 +305,26 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar for (const auto& sourceImpl : *sourceImpls) { RenderSource* source = renderSources.at(sourceImpl->id).get(); bool sourceNeedsRendering = false; - bool sourceNeedsRelayout = false; - - uint32_t index = 0u; - const auto begin = layerImpls->begin(); - const auto end = layerImpls->end(); - for (auto it = begin; it != end; ++it, ++index) { - const Immutable& layerImpl = *it; - RenderLayer* layer = getRenderLayer(layerImpl->id); - const auto* layerInfo = layerImpl->getTypeInfo(); - const bool layerIsVisible = layer->baseImpl->visibility != style::VisibilityType::None; - const bool zoomFitsLayer = layer->supportsZoom(zoomHistory.lastZoom); + bool sourceNeedsRelayout = false; + + for (uint32_t index = 0u; index < orderedLayers.size(); ++index) { + RenderLayer& layer = orderedLayers[index]; + const auto* layerInfo = layer.baseImpl->getTypeInfo(); + const bool layerIsVisible = layer.baseImpl->visibility != style::VisibilityType::None; + const bool zoomFitsLayer = layer.supportsZoom(zoomHistory.lastZoom); renderTreeParameters->has3D |= (layerInfo->pass3d == LayerTypeInfo::Pass3D::Required); if (layerInfo->source != LayerTypeInfo::Source::NotRequired) { - if (layerImpl->source == sourceImpl->id) { - sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || constantsMaskChanged.count(layerImpl->id) || hasLayoutDifference(layerDiff, layerImpl->id)); + if (layer.baseImpl->source == sourceImpl->id) { + const std::string& layerId = layer.getID(); + sourceNeedsRelayout = (sourceNeedsRelayout || hasImageDiff || constantsMaskChanged.count(layerId) || + hasLayoutDifference(layerDiff, layerId)); if (layerIsVisible) { - filteredLayersForSource.push_back(layer->evaluatedProperties); + filteredLayersForSource.push_back(layer.evaluatedProperties); if (zoomFitsLayer) { sourceNeedsRendering = true; - renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, source, index); + renderItemsEmplaceHint = + layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, source, index); } } } @@ -322,14 +333,14 @@ std::unique_ptr RenderOrchestrator::createRenderTree(const UpdatePar // Handle layers without source. if (layerIsVisible && zoomFitsLayer && sourceImpl.get() == sourceImpls->at(0).get()) { - if (backgroundLayerAsColor && layerImpl.get() == layerImpls->at(0).get()) { - const auto& solidBackground = layer->getSolidBackground(); + if (backgroundLayerAsColor && layer.baseImpl == layerImpls->front()) { + const auto& solidBackground = layer.getSolidBackground(); if (solidBackground) { renderTreeParameters->backgroundColor = *solidBackground; continue; // This layer is shown with background color, and it shall not be added to render items. } } - renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, *layer, nullptr, index); + renderItemsEmplaceHint = layerRenderItems.emplace_hint(renderItemsEmplaceHint, layer, nullptr, index); } } source->update(sourceImpl, diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp index 9b63498a2a..c2b44c2792 100644 --- a/src/mbgl/renderer/render_orchestrator.hpp +++ b/src/mbgl/renderer/render_orchestrator.hpp @@ -127,9 +127,11 @@ private: const bool backgroundLayerAsColor; bool contextLost = false; - // Vector with reserved capacity of layerImpls->size() to avoid reallocation + // Vectors with reserved capacity of layerImpls->size() to avoid reallocation // on each frame. std::vector> filteredLayersForSource; + std::vector> orderedLayers; + std::vector> layersNeedPlacement; }; } // namespace mbgl -- cgit v1.2.1 From 946b9d22818c76325ce6f5bf4804494f461f2c0a Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 4 Oct 2019 12:34:30 +0300 Subject: [ios][android] Add change log entries --- platform/android/CHANGELOG.md | 3 +++ platform/ios/CHANGELOG.md | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index e28b5849e7..e3b07dd32e 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,6 +4,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master +### Performance improvements + - Improved rendering performance for the styles with multiple sources [#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756) + ## 8.5.0-alpha.1 - October 3, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0...android-v8.5.0-alpha.1) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0): ### Bug fixes diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index d8d242e5ea..458e533442 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. +## master + +### Performance improvements + + * Improved rendering performance for the styles with multiple sources ([#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756)) + ## 5.5.0 ### Other changes -- cgit v1.2.1 From 198e3453394ccb2b1f7db72d1858cfd18e302a1e Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Fri, 4 Oct 2019 11:56:26 +0300 Subject: [android] Check if Mapbox instance exists before creating default file source This check is needed for mbgl-benchmark target, as it does not require Mapbox instance, nor Android asset manager. --- platform/android/src/file_source.cpp | 11 ++++++++--- platform/android/src/mapbox.cpp | 6 ++++++ platform/android/src/mapbox.hpp | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp index 234d8d9758..a002d6616f 100644 --- a/platform/android/src/file_source.cpp +++ b/platform/android/src/file_source.cpp @@ -17,9 +17,14 @@ namespace mbgl { std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { auto env{android::AttachEnv()}; - auto assetManager = android::Mapbox::getAssetManager(*env); - auto fileSource = std::make_shared(options.cachePath(), - std::make_unique(*env, assetManager)); + std::shared_ptr fileSource; + if (android::Mapbox::hasInstance(*env)) { + auto assetManager = android::Mapbox::getAssetManager(*env); + fileSource = std::make_shared(options.cachePath(), + std::make_unique(*env, assetManager)); + } else { + fileSource = std::make_shared(options.cachePath(), options.assetPath()); + } fileSource->setAccessToken(options.accessToken()); return fileSource; } diff --git a/platform/android/src/mapbox.cpp b/platform/android/src/mapbox.cpp index c835518b42..5246739cf6 100644 --- a/platform/android/src/mapbox.cpp +++ b/platform/android/src/mapbox.cpp @@ -9,6 +9,12 @@ jni::Local> Mapbox::getAssetManager(jni::JNIEnv& env) return javaClass.Call(env, method); } +jboolean Mapbox::hasInstance(jni::JNIEnv& env) { + static auto& javaClass = jni::Class::Singleton(env); + auto method = javaClass.GetStaticMethod(env, "hasInstance"); + return javaClass.Call(env, method); +} + void Mapbox::registerNative(jni::JNIEnv& env) { jni::Class::Singleton(env); } diff --git a/platform/android/src/mapbox.hpp b/platform/android/src/mapbox.hpp index 2d9a657fa1..813f5bf174 100644 --- a/platform/android/src/mapbox.hpp +++ b/platform/android/src/mapbox.hpp @@ -10,6 +10,7 @@ namespace android { class Mapbox { public: static constexpr auto Name() { return "com/mapbox/mapboxsdk/Mapbox"; }; + static jboolean hasInstance(jni::JNIEnv&); static jni::Local> getAssetManager(jni::JNIEnv&); static void registerNative(jni::JNIEnv&); }; -- cgit v1.2.1 From bef635765a1bbec14d7732856c38c037ea8add6a Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 4 Oct 2019 12:30:41 +0300 Subject: [core] Decouple Scheduler interface from actor model So that it is possible to schedule normal `std::function` and use `mapbox::base::WeakPtr`. --- include/mbgl/actor/mailbox.hpp | 2 ++ include/mbgl/actor/scheduler.hpp | 10 ++++------ include/mbgl/util/run_loop.hpp | 8 ++------ platform/android/src/map_renderer.cpp | 2 +- platform/android/src/map_renderer.hpp | 2 +- platform/android/src/map_renderer_runnable.cpp | 7 +++---- platform/android/src/map_renderer_runnable.hpp | 4 ++-- platform/qt/src/qmapboxgl_scheduler.cpp | 10 +++++----- platform/qt/src/qmapboxgl_scheduler.hpp | 5 ++--- src/mbgl/actor/mailbox.cpp | 12 +++++++++--- src/mbgl/util/thread_pool.cpp | 9 ++++----- src/mbgl/util/thread_pool.hpp | 4 ++-- test/actor/actor.test.cpp | 2 +- 13 files changed, 38 insertions(+), 39 deletions(-) diff --git a/include/mbgl/actor/mailbox.hpp b/include/mbgl/actor/mailbox.hpp index 23c579917a..2b9838ef29 100644 --- a/include/mbgl/actor/mailbox.hpp +++ b/include/mbgl/actor/mailbox.hpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -34,6 +35,7 @@ public: void receive(); static void maybeReceive(std::weak_ptr); + static std::function makeClosure(std::weak_ptr); private: optional scheduler; diff --git a/include/mbgl/actor/scheduler.hpp b/include/mbgl/actor/scheduler.hpp index 6470ab1245..ca34901cfd 100644 --- a/include/mbgl/actor/scheduler.hpp +++ b/include/mbgl/actor/scheduler.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include namespace mbgl { @@ -31,12 +32,9 @@ class Mailbox; class Scheduler { public: virtual ~Scheduler() = default; - - // Used by a Mailbox when it has a message in its queue to request that it - // be scheduled. Specifically, the scheduler is expected to asynchronously - // call `receive() on the given mailbox, provided it still exists at that - // time. - virtual void schedule(std::weak_ptr) = 0; + + // Enqueues a function for execution. + virtual void schedule(std::function) = 0; // Set/Get the current Scheduler for this thread static Scheduler* GetCurrent(); diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp index 381e3ae213..961573fd87 100644 --- a/include/mbgl/util/run_loop.hpp +++ b/include/mbgl/util/run_loop.hpp @@ -72,12 +72,8 @@ public: push(Priority::Default, task); return std::make_unique(task); } - - void schedule(std::weak_ptr mailbox) override { - invoke([mailbox] () { - Mailbox::maybeReceive(mailbox); - }); - } + + void schedule(std::function fn) override { invoke(std::move(fn)); } class Impl; diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp index 6be708b994..0c0e907f14 100644 --- a/platform/android/src/map_renderer.cpp +++ b/platform/android/src/map_renderer.cpp @@ -43,7 +43,7 @@ ActorRef MapRenderer::actor() const { return *rendererRef; } -void MapRenderer::schedule(std::weak_ptr scheduled) { +void MapRenderer::schedule(std::function scheduled) { // Create a runnable android::UniqueEnv _env = android::AttachEnv(); auto runnable = std::make_unique(*_env, std::move(scheduled)); diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index 5a8ddeeb91..664da20a94 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -67,7 +67,7 @@ public: // From Scheduler. Schedules by using callbacks to the // JVM to process the mailbox on the right thread. - void schedule(std::weak_ptr scheduled) override; + void schedule(std::function scheduled) override; void requestRender(); diff --git a/platform/android/src/map_renderer_runnable.cpp b/platform/android/src/map_renderer_runnable.cpp index 77c3aa301d..227f49ee3f 100644 --- a/platform/android/src/map_renderer_runnable.cpp +++ b/platform/android/src/map_renderer_runnable.cpp @@ -5,9 +5,8 @@ namespace mbgl { namespace android { -MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr mailbox_) - : mailbox(std::move(mailbox_)) { - +MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::function function_) + : function(std::move(function_)) { // Create the Java peer and hold on to a global reference // Not using a weak reference here as this might oerflow // the weak reference table on some devices @@ -21,7 +20,7 @@ MapRendererRunnable::MapRendererRunnable(jni::JNIEnv& env, std::weak_ptr> MapRendererRunnable::peer() { diff --git a/platform/android/src/map_renderer_runnable.hpp b/platform/android/src/map_renderer_runnable.hpp index 21c4369b69..24d0f2af49 100644 --- a/platform/android/src/map_renderer_runnable.hpp +++ b/platform/android/src/map_renderer_runnable.hpp @@ -24,7 +24,7 @@ public: static void registerNative(jni::JNIEnv&); - MapRendererRunnable(jni::JNIEnv&, std::weak_ptr); + MapRendererRunnable(jni::JNIEnv&, std::function); // Only for jni registration, unused MapRendererRunnable(jni::JNIEnv&) { @@ -40,7 +40,7 @@ public: private: jni::Global> javaPeer; - std::weak_ptr mailbox; + std::function function; }; } // namespace android diff --git a/platform/qt/src/qmapboxgl_scheduler.cpp b/platform/qt/src/qmapboxgl_scheduler.cpp index e2d39703ee..5fc3ab13de 100644 --- a/platform/qt/src/qmapboxgl_scheduler.cpp +++ b/platform/qt/src/qmapboxgl_scheduler.cpp @@ -13,10 +13,9 @@ QMapboxGLScheduler::~QMapboxGLScheduler() MBGL_VERIFY_THREAD(tid); } -void QMapboxGLScheduler::schedule(std::weak_ptr mailbox) -{ +void QMapboxGLScheduler::schedule(std::function function) { std::lock_guard lock(m_taskQueueMutex); - m_taskQueue.push(mailbox); + m_taskQueue.push(std::move(function)); // Need to force the main thread to wake // up this thread and process the events. @@ -25,14 +24,15 @@ void QMapboxGLScheduler::schedule(std::weak_ptr mailbox) void QMapboxGLScheduler::processEvents() { - std::queue> taskQueue; + std::queue> taskQueue; { std::unique_lock lock(m_taskQueueMutex); std::swap(taskQueue, m_taskQueue); } while (!taskQueue.empty()) { - mbgl::Mailbox::maybeReceive(taskQueue.front()); + auto& function = taskQueue.front(); + if (function) function(); taskQueue.pop(); } } diff --git a/platform/qt/src/qmapboxgl_scheduler.hpp b/platform/qt/src/qmapboxgl_scheduler.hpp index 68636d0d11..b34dd3d5b8 100644 --- a/platform/qt/src/qmapboxgl_scheduler.hpp +++ b/platform/qt/src/qmapboxgl_scheduler.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -19,7 +18,7 @@ public: virtual ~QMapboxGLScheduler(); // mbgl::Scheduler implementation. - void schedule(std::weak_ptr scheduled) final; + void schedule(std::function scheduled) final; void processEvents(); @@ -30,5 +29,5 @@ private: MBGL_STORE_THREAD(tid); std::mutex m_taskQueueMutex; - std::queue> m_taskQueue; + std::queue> m_taskQueue; }; diff --git a/src/mbgl/actor/mailbox.cpp b/src/mbgl/actor/mailbox.cpp index dfe0520790..070e14bdb0 100644 --- a/src/mbgl/actor/mailbox.cpp +++ b/src/mbgl/actor/mailbox.cpp @@ -27,7 +27,7 @@ void Mailbox::open(Scheduler& scheduler_) { } if (!queue.empty()) { - (*scheduler)->schedule(shared_from_this()); + (*scheduler)->schedule(makeClosure(shared_from_this())); } } @@ -57,7 +57,7 @@ void Mailbox::push(std::unique_ptr message) { bool wasEmpty = queue.empty(); queue.push(std::move(message)); if (wasEmpty && scheduler) { - (*scheduler)->schedule(shared_from_this()); + (*scheduler)->schedule(makeClosure(shared_from_this())); } } @@ -84,14 +84,20 @@ void Mailbox::receive() { (*message)(); if (!wasEmpty) { - (*scheduler)->schedule(shared_from_this()); + (*scheduler)->schedule(makeClosure(shared_from_this())); } } +// static void Mailbox::maybeReceive(std::weak_ptr mailbox) { if (auto locked = mailbox.lock()) { locked->receive(); } } +// static +std::function Mailbox::makeClosure(std::weak_ptr mailbox) { + return [mailbox]() { maybeReceive(mailbox); }; +} + } // namespace mbgl diff --git a/src/mbgl/util/thread_pool.cpp b/src/mbgl/util/thread_pool.cpp index e839d1b4be..d8df0cd575 100644 --- a/src/mbgl/util/thread_pool.cpp +++ b/src/mbgl/util/thread_pool.cpp @@ -26,11 +26,10 @@ ThreadPool::ThreadPool(std::size_t count) { return; } - auto mailbox = queue.front(); + auto function = std::move(queue.front()); queue.pop(); lock.unlock(); - - Mailbox::maybeReceive(mailbox); + if (function) function(); } }); } @@ -49,10 +48,10 @@ ThreadPool::~ThreadPool() { } } -void ThreadPool::schedule(std::weak_ptr mailbox) { +void ThreadPool::schedule(std::function fn) { { std::lock_guard lock(mutex); - queue.push(mailbox); + queue.push(std::move(fn)); } cv.notify_one(); diff --git a/src/mbgl/util/thread_pool.hpp b/src/mbgl/util/thread_pool.hpp index 509fd06061..96fc13bda5 100644 --- a/src/mbgl/util/thread_pool.hpp +++ b/src/mbgl/util/thread_pool.hpp @@ -15,11 +15,11 @@ public: explicit ThreadPool(std::size_t count); ~ThreadPool() override; - void schedule(std::weak_ptr) override; + void schedule(std::function) override; private: std::vector threads; - std::queue> queue; + std::queue> queue; std::mutex mutex; std::condition_variable cv; bool terminate{ false }; diff --git a/test/actor/actor.test.cpp b/test/actor/actor.test.cpp index 6db95a83f1..4b152f471a 100644 --- a/test/actor/actor.test.cpp +++ b/test/actor/actor.test.cpp @@ -101,7 +101,7 @@ TEST(Actor, DestructionBlocksOnSend) { EXPECT_TRUE(waited.load()); } - void schedule(std::weak_ptr) final { + void schedule(std::function) final { promise.set_value(); future.wait(); std::this_thread::sleep_for(1ms); -- cgit v1.2.1 From cab756374f4eb42ab632c6db6d049a90884700ad Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Fri, 4 Oct 2019 11:15:20 -0400 Subject: [ios] Fix layout of Scale bar components (#15703) * [ios] Add failing tests for scale bar updates. * [ios] Remove borderLayer * [ios] Ensure bar sections have non-fractional width * [ios] Add RTL override * [ios] Update constraints/layout * [ios] Invalidate scalebars size, after the parent's layout has happened (to ensure the view dimensions are correct when re-laying out the scale bar. * [ios] Refactor layout * [ios] Update changelog / remove commented code. * [ios] Remove whitespace * [ios] Stop integration tests asserting (when scale bar is hidden). Also reduces the # of calculations (since updateConstraints and layoutSubviews can be called outside of our control). * [ios] Moves declaration of properties for testing. * [ios] Removes redundant property attribute * [ios] Updated change log --- platform/ios/CHANGELOG.md | 1 + platform/ios/src/MGLMapView.mm | 21 ++- platform/ios/src/MGLScaleBar.mm | 221 +++++++++++++++++++++------- platform/ios/test/MGLMapViewLayoutTests.m | 85 ++++++++++- platform/ios/test/MGLMapViewScaleBarTests.m | 15 +- 5 files changed, 269 insertions(+), 74 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 458e533442..d636d94811 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -13,6 +13,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Other changes * Suppress network requests for expired tiles update, if these tiles are invisible. ([#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741)) +* Fixed an issue that caused `MGLScaleBar` to have an incorrect size when resizing or rotating. ([#15703](https://github.com/mapbox/mapbox-gl-native/pull/15703)) ## 5.4.0 - September 25, 2019 diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 62b943fd3d..76cec479bb 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -852,9 +852,11 @@ public: break; } - [updatedConstraints addObject:[view.widthAnchor constraintEqualToConstant:size.width]]; - [updatedConstraints addObject:[view.heightAnchor constraintEqualToConstant:size.height]]; - + if (!CGSizeEqualToSize(size, CGSizeZero)) { + [updatedConstraints addObject:[view.widthAnchor constraintEqualToConstant:size.width]]; + [updatedConstraints addObject:[view.heightAnchor constraintEqualToConstant:size.height]]; + } + [NSLayoutConstraint deactivateConstraints:constraints]; [constraints removeAllObjects]; [NSLayoutConstraint activateConstraints:updatedConstraints]; @@ -883,7 +885,7 @@ public: [self updateConstraintsForOrnament:self.scaleBar constraints:self.scaleBarConstraints position:self.scaleBarPosition - size:self.scaleBar.intrinsicContentSize + size:CGSizeZero margins:self.scaleBarMargins]; } @@ -929,15 +931,14 @@ public: // This gets called when the view dimension changes, e.g. because the device is being rotated. - (void)layoutSubviews { + [super layoutSubviews]; + // Calling this here instead of in the scale bar itself because if this is done in the // scale bar instance, it triggers a call to this `layoutSubviews` method that calls // `_mbglMap->setSize()` just below that triggers rendering update which triggers // another scale bar update which causes a rendering update loop and a major performace - // degradation. The only time the scale bar's intrinsic content size _must_ invalidated - // is here as a reaction to this object's view dimension changes. + // degradation. [self.scaleBar invalidateIntrinsicContentSize]; - - [super layoutSubviews]; [self adjustContentInset]; @@ -6642,11 +6643,7 @@ public: // setting this property. if ( ! self.scaleBar.hidden) { - CGSize originalSize = self.scaleBar.intrinsicContentSize; [(MGLScaleBar *)self.scaleBar setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]]; - if ( ! CGSizeEqualToSize(originalSize, self.scaleBar.intrinsicContentSize)) { - [self installScaleBarConstraints]; - } } } diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm index 8525881da7..3efa80013f 100644 --- a/platform/ios/src/MGLScaleBar.mm +++ b/platform/ios/src/MGLScaleBar.mm @@ -82,16 +82,20 @@ static const MGLRow MGLImperialTable[] ={ @property (nonatomic, assign) MGLRow row; @property (nonatomic) UIColor *primaryColor; @property (nonatomic) UIColor *secondaryColor; -@property (nonatomic) CALayer *borderLayer; @property (nonatomic, assign) CGFloat borderWidth; @property (nonatomic) NSMutableDictionary* labelImageCache; @property (nonatomic) MGLScaleBarLabel* prototypeLabel; @property (nonatomic) CGFloat lastLabelWidth; - +@property (nonatomic) CGSize size; +@property (nonatomic) BOOL recalculateSize; +@property (nonatomic) BOOL shouldLayoutBars; +@property (nonatomic) NSNumber *testingRightToLeftOverride; @end static const CGFloat MGLBarHeight = 4; static const CGFloat MGLFeetPerMeter = 3.28084; +static const CGFloat MGLScaleBarLabelWidthHint = 30.0; +static const CGFloat MGLScaleBarMinimumBarWidth = 30.0; // Arbitrary @interface MGLScaleBarLabel : UILabel @@ -137,6 +141,8 @@ static const CGFloat MGLFeetPerMeter = 3.28084; } - (void)commonInit { + _size = CGSizeZero; + _primaryColor = [UIColor colorWithRed:18.0/255.0 green:45.0/255.0 blue:17.0/255.0 alpha:1]; _secondaryColor = [UIColor colorWithRed:247.0/255.0 green:247.0/255.0 blue:247.0/255.0 alpha:1]; _borderWidth = 1.0f; @@ -144,17 +150,17 @@ static const CGFloat MGLFeetPerMeter = 3.28084; self.clipsToBounds = NO; self.hidden = YES; - _containerView = [[UIView alloc] init]; - _containerView.clipsToBounds = YES; - _containerView.backgroundColor = self.secondaryColor; + _containerView = [[UIView alloc] init]; + _containerView.clipsToBounds = YES; + _containerView.backgroundColor = _secondaryColor; + _containerView.layer.borderColor = _primaryColor.CGColor; + _containerView.layer.borderWidth = _borderWidth / [[UIScreen mainScreen] scale]; + + _containerView.layer.cornerRadius = MGLBarHeight / 2.0; + _containerView.layer.masksToBounds = YES; + [self addSubview:_containerView]; - _borderLayer = [CAShapeLayer layer]; - _borderLayer.borderColor = [self.primaryColor CGColor]; - _borderLayer.borderWidth = 1.0f / [[UIScreen mainScreen] scale]; - - [_containerView.layer addSublayer:_borderLayer]; - _formatter = [[MGLDistanceFormatter alloc] init]; // Image labels are now images @@ -176,6 +182,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084; [self addSubview:view]; } _labelViews = [labelViews copy]; + _lastLabelWidth = MGLScaleBarLabelWidthHint; // Zero is a special case (no formatting) [self addZeroLabel]; @@ -194,16 +201,33 @@ static const CGFloat MGLFeetPerMeter = 3.28084; #pragma mark - Dimensions -- (CGSize)intrinsicContentSize { - return self.actualWidth > 0 ? CGSizeMake(ceil(self.actualWidth + self.lastLabelWidth/2), 16) : CGSizeZero; +- (void)setBorderWidth:(CGFloat)borderWidth { + _borderWidth = borderWidth; + _containerView.layer.borderWidth = borderWidth / [[UIScreen mainScreen] scale]; } +// Determines the width of the bars NOT the size of the entire scale bar, +// which includes space for (half) a label. +// Uses the current set `row` - (CGFloat)actualWidth { - CGFloat width = self.row.distance / [self unitsPerPoint]; - return !isnan(width) ? width : 0; + CGFloat unitsPerPoint = [self unitsPerPoint]; + + if (unitsPerPoint == 0.0) { + return 0.0; + } + + CGFloat width = self.row.distance / unitsPerPoint; + + if (width <= MGLScaleBarMinimumBarWidth) { + return 0.0; + } + + // Round, so that each bar section has an integer width + return self.row.numberOfBars * floor(width/self.row.numberOfBars); } - (CGFloat)maximumWidth { + // TODO: Consider taking Scale Bar margins into account here. CGFloat fullWidth = CGRectGetWidth(self.superview.bounds); return floorf(fullWidth / 2); } @@ -215,6 +239,10 @@ static const CGFloat MGLFeetPerMeter = 3.28084; #pragma mark - Convenience methods - (BOOL)usesRightToLeftLayout { + if (self.testingRightToLeftOverride) { + return [self.testingRightToLeftOverride boolValue]; + } + return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft; } @@ -265,10 +293,61 @@ static const CGFloat MGLFeetPerMeter = 3.28084; [self updateVisibility]; + self.recalculateSize = YES; + [self invalidateIntrinsicContentSize]; +} + +- (CGSize)intrinsicContentSize { + // Size is calculated elsewhere - since intrinsicContentSize is part of the + // constraint system, this should be done in updateConstraints + if (self.size.width < 0.0) { + return CGSizeZero; + } + return self.size; +} + +/// updateConstraints +/// +/// The primary job of updateConstraints here is to recalculate the +/// intrinsicContentSize: _metersPerPoint and the maximum width determine the +/// current "row", which in turn determines the "actualWidth". To obtain the full +/// width of the scale bar, we also need to include some space for the "last" +/// label + +- (void)updateConstraints { + if (self.isHidden || !self.recalculateSize) { + [super updateConstraints]; + return; + } + + // TODO: Improve this (and the side-effects) self.row = [self preferredRow]; - [self invalidateIntrinsicContentSize]; + NSAssert(self.row.numberOfBars > 0, @""); + + CGFloat totalBarWidth = self.actualWidth; + + if (totalBarWidth <= 0.0) { + [super updateConstraints]; + return; + } + + // Determine the "lastLabelWidth". This has changed to take a maximum of each + // label, to ensure that the size does not change in LTR & RTL layouts, and + // also to stop jiggling when the scale bar is on the right hand of the screen + // This will most likely be a constant, as we take a max using a "hint" for + // the initial value + + if (self.shouldLayoutBars) { + [self updateLabels]; + } + + CGFloat halfLabelWidth = ceil(self.lastLabelWidth/2); + + self.size = CGSizeMake(totalBarWidth + halfLabelWidth, 16); + [self setNeedsLayout]; + [super updateConstraints]; // This calls intrinsicContentSize } - (void)updateVisibility { @@ -297,11 +376,9 @@ static const CGFloat MGLFeetPerMeter = 3.28084; return; } + self.shouldLayoutBars = YES; + _row = row; - [_bars makeObjectsPerformSelector:@selector(removeFromSuperview)]; - _bars = nil; - - [self updateLabels]; } #pragma mark - Views @@ -378,9 +455,9 @@ static const CGFloat MGLFeetPerMeter = 3.28084; CLLocationDistance barDistance = multiplier * i; UIImage *image = [self cachedLabelImageForDistance:barDistance]; - if (i == self.row.numberOfBars) { - self.lastLabelWidth = image.size.width; - } + + self.lastLabelWidth = MAX(self.lastLabelWidth, image.size.width); + labelView.layer.contents = (id)image.CGImage; labelView.layer.contentsScale = image.scale; } @@ -397,53 +474,83 @@ static const CGFloat MGLFeetPerMeter = 3.28084; - (void)layoutSubviews { [super layoutSubviews]; - if (!self.row.numberOfBars) { - // Current distance is not within allowed range + if (!self.recalculateSize) { return; } - [self layoutBars]; - [self layoutLabels]; -} + self.recalculateSize = NO; + + // If size is 0, then we keep the existing layout (which will fade out) + if (self.size.width <= 0.0) { + return; + } + + CGFloat totalBarWidth = self.actualWidth; + + if (totalBarWidth <= 0.0) { + return; + } + + if (self.shouldLayoutBars) { + self.shouldLayoutBars = NO; + [_bars makeObjectsPerformSelector:@selector(removeFromSuperview)]; + _bars = nil; + } + + // Re-layout the component bars and labels of the scale bar + CGFloat intrinsicContentHeight = self.intrinsicContentSize.height; + CGFloat barWidth = totalBarWidth/self.bars.count; -- (void)layoutBars { - CGFloat barWidth = round((self.intrinsicContentSize.width - self.borderWidth * 2.0f) / self.bars.count); + BOOL RTL = [self usesRightToLeftLayout]; + CGFloat halfLabelWidth = ceil(self.lastLabelWidth/2); + CGFloat barOffset = RTL ? halfLabelWidth : 0.0; + self.containerView.frame = CGRectMake(barOffset, + intrinsicContentHeight - MGLBarHeight, + totalBarWidth, + MGLBarHeight); + + [self layoutBarsWithWidth:barWidth]; + + CGFloat yPosition = round(0.5 * ( intrinsicContentHeight - MGLBarHeight)); + CGFloat barDelta = RTL ? -barWidth : barWidth; + [self layoutLabelsWithOffset:barOffset delta:barDelta yPosition:yPosition]; +} + +- (void)layoutBarsWithWidth:(CGFloat)barWidth { NSUInteger i = 0; for (UIView *bar in self.bars) { - CGFloat xPosition = barWidth * i + self.borderWidth; + CGFloat xPosition = barWidth * i; bar.backgroundColor = (i % 2 == 0) ? self.primaryColor : self.secondaryColor; - bar.frame = CGRectMake(xPosition, self.borderWidth, barWidth, MGLBarHeight); + bar.frame = CGRectMake(xPosition, 0, barWidth, MGLBarHeight); i++; } - - self.containerView.frame = CGRectMake(CGRectGetMinX(self.bars.firstObject.frame), - self.intrinsicContentSize.height-MGLBarHeight, - self.actualWidth, - MGLBarHeight+self.borderWidth*2); - - [CATransaction begin]; - [CATransaction setDisableActions:YES]; - self.borderLayer.frame = CGRectInset(self.containerView.bounds, self.borderWidth, self.borderWidth); - self.borderLayer.zPosition = FLT_MAX; - [CATransaction commit]; } -- (void)layoutLabels { - CGFloat barWidth = round(self.actualWidth / self.bars.count); - BOOL RTL = [self usesRightToLeftLayout]; - NSUInteger i = RTL ? self.bars.count : 0; +- (void)layoutLabelsWithOffset:(CGFloat)barOffset delta:(CGFloat)barDelta yPosition:(CGFloat)yPosition { +#if !defined(NS_BLOCK_ASSERTIONS) + NSUInteger countOfVisibleLabels = 0; + for (UIView *view in self.labelViews) { + if (!view.isHidden) { + countOfVisibleLabels++; + } + } + NSAssert(self.bars.count == countOfVisibleLabels - 1, @""); +#endif + + CGFloat xPosition = barOffset; + + if (barDelta < 0) { + xPosition -= (barDelta*self.bars.count); + } + for (UIView *label in self.labelViews) { - CGFloat xPosition = round(barWidth * i - CGRectGetMidX(label.bounds) + self.borderWidth); - CGFloat yPosition = round(0.5 * (self.intrinsicContentSize.height - MGLBarHeight)); - - CGRect frame = label.frame; - frame.origin.x = xPosition; - frame.origin.y = yPosition; - label.frame = frame; - - i = RTL ? i-1 : i+1; + // Label frames have 0 size - though the layer contents use "center" and do + // not clip to bounds. This way we don't need to worry about positioning the + // label. (Though you won't see the label in the view debugger) + label.frame = CGRectMake(xPosition, yPosition, 0.0, 0.0); + + xPosition += barDelta; } } - @end diff --git a/platform/ios/test/MGLMapViewLayoutTests.m b/platform/ios/test/MGLMapViewLayoutTests.m index 5d9c0339b5..2a9579818a 100644 --- a/platform/ios/test/MGLMapViewLayoutTests.m +++ b/platform/ios/test/MGLMapViewLayoutTests.m @@ -3,6 +3,7 @@ #import "MGLMapViewDelegate.h" #import "MGLAccountManager.h" +#import "MGLScaleBar.h" @interface MGLOrnamentTestData : NSObject @@ -24,6 +25,14 @@ @end +@interface MGLScaleBar (Tests) +@property (nonatomic, readonly) NSArray *labelViews; +@property (nonatomic, readonly) NSArray *bars; +@property (nonatomic, readonly) UIView *containerView; +@property (nonatomic, readonly) CGSize size; +@property (nonatomic) NSNumber *testingRightToLeftOverride; +@end + @interface MGLMapViewLayoutTests : XCTestCase @@ -140,7 +149,7 @@ expectedOrigin:CGPointMake(margin, margin)], [MGLOrnamentTestData createWithPosition:MGLOrnamentPositionTopRight offset:CGPointMake(margin, margin) - expectedOrigin:CGPointMake(CGRectGetMaxX(self.mapView.bounds) - margin - CGRectGetWidth(view.frame), 4)], + expectedOrigin:CGPointMake(CGRectGetMaxX(self.mapView.bounds) - margin - CGRectGetWidth(view.frame), margin)], [MGLOrnamentTestData createWithPosition:MGLOrnamentPositionBottomLeft offset:CGPointMake(margin, margin) expectedOrigin:CGPointMake(margin, CGRectGetMaxY(self.mapView.bounds) - margin - bottomSafeAreaInset - CGRectGetHeight(view.frame))], @@ -176,6 +185,8 @@ CGFloat margin = 4.0; UIView *scaleBar = self.mapView.scaleBar; + XCTAssertFalse(CGSizeEqualToSize(scaleBar.bounds.size, CGSizeZero)); + NSArray *testDataList = [self makeTestDataListWithView:scaleBar margin:margin]; for (MGLOrnamentTestData *testData in testDataList) { @@ -191,6 +202,78 @@ } } +// This test checks the frames of the scalebar's subviews, based on the positions +// as above, but also with forced Right-to-Left reading, and modifying zoom levels. +- (void)testScalebarSubviewPlacement { + double accuracy = 0.01; + CGFloat margin = 20.0; + + MGLScaleBar *scaleBar = (MGLScaleBar*)self.mapView.scaleBar; + XCTAssertFalse(CGSizeEqualToSize(scaleBar.bounds.size, CGSizeZero)); + + for (NSInteger rtl = 0; rtl <= 1; rtl++) { + scaleBar.testingRightToLeftOverride = @((BOOL)rtl); + + NSString *positions[] = { + @"MGLOrnamentPositionTopLeft", + @"MGLOrnamentPositionTopRight", + @"MGLOrnamentPositionBottomLeft", + @"MGLOrnamentPositionBottomRight" + }; + + for (CGFloat zoomLevel = 0; zoomLevel < 20; zoomLevel++) + { + self.mapView.zoomLevel = zoomLevel; + [self.superView setNeedsLayout]; + [self.superView layoutIfNeeded]; + + // Following method assumes scaleBar has an up-to-date frame, based + // on the current zoom level. Modifying the position and margins + // should not affect the overall size of the scalebar. + + NSArray *testDataList = [self makeTestDataListWithView:scaleBar margin:margin]; + + CGSize initialSize = scaleBar.intrinsicContentSize; + XCTAssert(CGSizeEqualToSize(initialSize, scaleBar.bounds.size)); + + for (MGLOrnamentTestData *testData in testDataList) { + self.mapView.scaleBarPosition = testData.position; + self.mapView.scaleBarMargins = testData.offset; + + [self.superView setNeedsLayout]; + [self.superView layoutIfNeeded]; + + XCTAssert(CGSizeEqualToSize(initialSize, scaleBar.bounds.size)); + + NSString *activityName = [NSString stringWithFormat: + @"Scalebar subview tests: RTL=%@, Zoom=%ld, POS=%@, Visible=%@", + (rtl == 0 ? @"NO" : @"YES"), + (long)zoomLevel, + positions[testData.position], + scaleBar.alpha > 0.0 ? @"YES" : @"NO"]; + + [XCTContext runActivityNamed:activityName + block:^(id activity) { + + // Check the subviews + XCTAssertEqualWithAccuracy(CGRectGetMinX(scaleBar.frame), testData.expectedOrigin.x, accuracy); + XCTAssertEqualWithAccuracy(CGRectGetMinY(scaleBar.frame), testData.expectedOrigin.y, accuracy); + + XCTAssertTrue(CGRectContainsRect(scaleBar.bounds, scaleBar.containerView.frame)); + for (UIView *bar in scaleBar.bars) { + XCTAssertTrue(CGRectContainsRect(scaleBar.containerView.bounds, bar.frame)); + } + for (UIView *label in scaleBar.labelViews) { + if (!label.isHidden) { + XCTAssertTrue(CGRectContainsRect(scaleBar.bounds, label.frame)); + } + } + }]; + } + } + } +} + - (void)testAttributionButtonPlacement { double accuracy = 0.01; CGFloat margin = 4.0; diff --git a/platform/ios/test/MGLMapViewScaleBarTests.m b/platform/ios/test/MGLMapViewScaleBarTests.m index 29acc75d7f..b4f81ef62b 100644 --- a/platform/ios/test/MGLMapViewScaleBarTests.m +++ b/platform/ios/test/MGLMapViewScaleBarTests.m @@ -36,11 +36,14 @@ XCTAssertFalse(scaleBar.hidden); // Scale bar should not be visible at default zoom (~z0), but it should be ready. - XCTAssertFalse(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); + // Size is not a measure of readiness here though. + XCTAssertTrue(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); XCTAssertEqual(scaleBar.alpha, 0); self.mapView.zoomLevel = 15; + [self.mapView layoutIfNeeded]; XCTAssertGreaterThan(scaleBar.alpha, 0); + XCTAssertFalse(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); } - (void)testDirectlySettingScaleBarViewHiddenProperty { @@ -54,10 +57,14 @@ // ... but triggering any camera event will update it. self.mapView.zoomLevel = 1; - XCTAssertFalse(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); + [self.mapView layoutIfNeeded]; + + XCTAssertTrue(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); XCTAssertEqual(scaleBar.alpha, 0); self.mapView.zoomLevel = 15; + [self.mapView layoutIfNeeded]; + XCTAssertGreaterThan(scaleBar.alpha, 0); -} -@end + XCTAssertFalse(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); +}@end -- cgit v1.2.1 From 910e34b85527f9caf074da2274ba4fc5d8c87f94 Mon Sep 17 00:00:00 2001 From: tobrun Date: Fri, 4 Oct 2019 16:03:42 +0200 Subject: [android] keep Mapbox.java when obfuscating code to allow look up from JNI --- .../MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 9c2ae8492c..35f7a5975d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.AssetManager; +import android.support.annotation.Keep; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; @@ -25,6 +26,7 @@ import com.mapbox.mapboxsdk.utils.ThreadUtils; */ @UiThread @SuppressLint("StaticFieldLeak") +@Keep public final class Mapbox { private static final String TAG = "Mbgl-Mapbox"; -- cgit v1.2.1 From 33a70100b839793311ecc73c873c063c7cf65e31 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Fri, 4 Oct 2019 13:51:40 -0400 Subject: [ios] Adds pointForCoordinate/coordinateForPoint to MGLMapSnapshotOverlay (#15746) * [ios] Adds `pointForCoordinate:`/`coordinateForPoint:` to MGLMapSnapshotOverlay * [ios] Adds PR # * [ios, macos] Update file lists & mac contexts * [macos] Fix for image scale in overlay. * [ios] Updated change log based on PR feedback. --- platform/darwin/src/MGLMapSnapshotter.h | 25 ++++++++ platform/darwin/src/MGLMapSnapshotter.mm | 66 +++++++++++++++++--- platform/darwin/src/MGLMapSnapshotter_Private.h | 14 +++++ platform/ios/CHANGELOG.md | 1 + .../Snapshotter Tests/MGLMapSnapshotterTest.m | 72 ++++++++++++++++++++++ platform/ios/ios.xcodeproj/project.pbxproj | 10 ++- platform/ios/sdk-files.json | 1 + 7 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 platform/darwin/src/MGLMapSnapshotter_Private.h diff --git a/platform/darwin/src/MGLMapSnapshotter.h b/platform/darwin/src/MGLMapSnapshotter.h index 33febe0d0c..98c8e8a375 100644 --- a/platform/darwin/src/MGLMapSnapshotter.h +++ b/platform/darwin/src/MGLMapSnapshotter.h @@ -19,6 +19,31 @@ MGL_EXPORT */ @property (nonatomic, readonly) CGContextRef context; +#if TARGET_OS_IPHONE +/** + Converts the specified map coordinate to a point in the coordinate space of the + context. + */ +- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + Converts the specified context point to a map coordinate. + */ +- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point; + +#else +/** + Converts the specified map coordinate to a point in the coordinate space of the + context. + */ +- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; + +/** + Converts the specified context point to a map coordinate. + */ +- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point; +#endif + @end /** diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm index 85619a780b..0dde94292c 100644 --- a/platform/darwin/src/MGLMapSnapshotter.mm +++ b/platform/darwin/src/MGLMapSnapshotter.mm @@ -17,6 +17,8 @@ #import "MGLAttributionInfo_Private.h" #import "MGLLoggingConfiguration_Private.h" #import "MGLRendererConfiguration.h" +#import "MGLMapSnapshotter_Private.h" + #if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR #import "MGLMapboxEvents.h" #endif @@ -33,23 +35,61 @@ const CGPoint MGLLogoImagePosition = CGPointMake(8, 8); const CGFloat MGLSnapshotterMinimumPixelSize = 64; -@interface MGLMapSnapshotOverlay() - -- (instancetype)initWithContext:(CGContextRef)context; +@interface MGLMapSnapshotOverlay() +@property (nonatomic, assign) CGFloat scale; +- (instancetype)initWithContext:(CGContextRef)context scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn; @end -@implementation MGLMapSnapshotOverlay +@implementation MGLMapSnapshotOverlay { + mbgl::MapSnapshotter::PointForFn _pointForFn; + mbgl::MapSnapshotter::LatLngForFn _latLngForFn; +} -- (instancetype) initWithContext:(CGContextRef)context { +- (instancetype) initWithContext:(CGContextRef)context scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn { self = [super init]; if (self) { _context = context; + _scale = scale; + _pointForFn = pointForFn; + _latLngForFn = latLngForFn; } return self; } +#if TARGET_OS_IPHONE + +- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate +{ + mbgl::ScreenCoordinate sc = _pointForFn(MGLLatLngFromLocationCoordinate2D(coordinate)); + return CGPointMake(sc.x, sc.y); +} + +- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point +{ + mbgl::LatLng latLng = _latLngForFn(mbgl::ScreenCoordinate(point.x, point.y)); + return MGLLocationCoordinate2DFromLatLng(latLng); +} + +#else + +- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate +{ + mbgl::ScreenCoordinate sc = _pointForFn(MGLLatLngFromLocationCoordinate2D(coordinate)); + CGFloat height = ((CGFloat)CGBitmapContextGetHeight(self.context))/self.scale; + return NSMakePoint(sc.x, height - sc.y); +} + +- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point +{ + CGFloat height = ((CGFloat)CGBitmapContextGetHeight(self.context))/self.scale; + auto screenCoord = mbgl::ScreenCoordinate(point.x, height - point.y); + mbgl::LatLng latLng = _latLngForFn(screenCoord); + return MGLLocationCoordinate2DFromLatLng(latLng); +} + +#endif @end @implementation MGLMapSnapshotOptions @@ -78,7 +118,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; @end -@interface MGLMapSnapshot() +@interface MGLMapSnapshot() - (instancetype)initWithImage:(nullable MGLImage *)image scale:(CGFloat)scale pointForFn:(mbgl::MapSnapshotter::PointForFn)pointForFn latLngForFn:(mbgl::MapSnapshotter::LatLngForFn)latLngForFn; @property (nonatomic) CGFloat scale; @@ -93,8 +133,8 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; { self = [super init]; if (self) { - _pointForFn = std::move(pointForFn); - _latLngForFn = std::move(latLngForFn); + _pointForFn = pointForFn; + _latLngForFn = latLngForFn; _scale = scale; _image = image; } @@ -328,7 +368,10 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; CGContextRef currentContext = UIGraphicsGetCurrentContext(); if (currentContext && overlayHandler) { - MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext]; + MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext + scale:scale + pointForFn:pointForFn + latLngForFn:latLngForFn]; CGContextSaveGState(snapshotOverlay.context); overlayHandler(snapshotOverlay); CGContextRestoreGState(snapshotOverlay.context); @@ -409,7 +452,10 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64; NSGraphicsContext *currentContext = [NSGraphicsContext currentContext]; if (currentContext && overlayHandler) { - MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext.CGContext]; + MGLMapSnapshotOverlay *snapshotOverlay = [[MGLMapSnapshotOverlay alloc] initWithContext:currentContext.CGContext + scale:scale + pointForFn:pointForFn + latLngForFn:latLngForFn]; [currentContext saveGraphicsState]; overlayHandler(snapshotOverlay); [currentContext restoreGraphicsState]; diff --git a/platform/darwin/src/MGLMapSnapshotter_Private.h b/platform/darwin/src/MGLMapSnapshotter_Private.h new file mode 100644 index 0000000000..205e51a6de --- /dev/null +++ b/platform/darwin/src/MGLMapSnapshotter_Private.h @@ -0,0 +1,14 @@ +#import "MGLMapSnapshotter.h" + +@protocol MGLMapSnapshotProtocol + +#if TARGET_OS_IPHONE +- (CGPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; +- (CLLocationCoordinate2D)coordinateForPoint:(CGPoint)point; + +#else +- (NSPoint)pointForCoordinate:(CLLocationCoordinate2D)coordinate; +- (CLLocationCoordinate2D)coordinateForPoint:(NSPoint)point; +#endif + +@end diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index d636d94811..d11c9a5f95 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -12,6 +12,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Other changes +* Added `-[MGLMapSnapshotOverlay coordinateForPoint:]` and `-[MGLMapSnapshotOverlay pointForCoordinate:]` to convert between context and map coordinates, mirroring those of `MGLMapSnapshot`. ([#15746](https://github.com/mapbox/mapbox-gl-native/pull/15746)) * Suppress network requests for expired tiles update, if these tiles are invisible. ([#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741)) * Fixed an issue that caused `MGLScaleBar` to have an incorrect size when resizing or rotating. ([#15703](https://github.com/mapbox/mapbox-gl-native/pull/15703)) diff --git a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m index 19718165b3..9ef2054dff 100644 --- a/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m +++ b/platform/ios/Integration Tests/Snapshotter Tests/MGLMapSnapshotterTest.m @@ -1,4 +1,5 @@ #import "MGLMapViewIntegrationTest.h" +#import "MGLMapSnapshotter_Private.h" @interface MGLMapSnapshotter () @property (nonatomic) BOOL cancelled; @@ -24,6 +25,21 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates return snapshotter; } +MGLMapSnapshotter* snapshotterWithBounds(MGLCoordinateBounds bounds, CGSize size) { + + MGLMapCamera* mapCamera = [[MGLMapCamera alloc] init]; + MGLMapSnapshotOptions* options = [[MGLMapSnapshotOptions alloc] initWithStyleURL:[MGLStyle satelliteStreetsStyleURL] + camera:mapCamera + size:size]; + options.coordinateBounds = bounds; + + // Create and start the snapshotter + MGLMapSnapshotter* snapshotter = [[MGLMapSnapshotter alloc] initWithOptions:options]; + return snapshotter; +} + + + @implementation MGLMapSnapshotterTest - (void)testMultipleSnapshotsWithASingleSnapshotter🔒 { @@ -462,4 +478,60 @@ MGLMapSnapshotter* snapshotterWithCoordinates(CLLocationCoordinate2D coordinates [self waitForExpectations:@[expectation] timeout:10.0]; } +- (void)testSnapshotCoordinatesWithOverlayHandler🔒 { + CGSize size = self.mapView.bounds.size; + + XCTestExpectation *expectation = [self expectationWithDescription:@"snapshot with overlay succeeds"]; + expectation.expectedFulfillmentCount = 2; + + CLLocationCoordinate2D london = { .latitude = 51.5074, .longitude = -0.1278 }; + CLLocationCoordinate2D paris = { .latitude = 48.8566, .longitude = 2.3522 }; + + MGLCoordinateBounds bounds = { + .ne = london, + .sw = paris + }; + + MGLMapSnapshotter *snapshotter = snapshotterWithBounds(bounds, size); + XCTAssertNotNil(snapshotter); + + void (^testCoordinates)(id) = ^(id snapshot){ + XCTAssertNotNil(snapshot); + + CGPoint londonPoint = [snapshot pointForCoordinate:london]; + CGPoint parisPoint = [snapshot pointForCoordinate:paris]; + + XCTAssertEqualWithAccuracy(londonPoint.x, 0, 0.1); + XCTAssertEqualWithAccuracy(parisPoint.x, size.width, 0.1); + + // Vertically, London and Paris are inset (due to the size vs coordinate bounds) + XCTAssert(parisPoint.y > londonPoint.y); + XCTAssert(londonPoint.y > 0.0); + XCTAssert(parisPoint.y < size.height); + + CLLocationCoordinate2D london2 = [snapshot coordinateForPoint:londonPoint]; + CLLocationCoordinate2D paris2 = [snapshot coordinateForPoint:parisPoint]; + + XCTAssertEqualWithAccuracy(london.latitude, london2.latitude, 0.0000001); + XCTAssertEqualWithAccuracy(london.longitude, london2.longitude, 0.0000001); + XCTAssertEqualWithAccuracy(paris.latitude, paris2.latitude, 0.0000001); + XCTAssertEqualWithAccuracy(paris.longitude, paris2.longitude, 0.0000001); + }; + + [snapshotter startWithOverlayHandler:^(MGLMapSnapshotOverlay *snapshotOverlay) { + XCTAssert([snapshotOverlay conformsToProtocol:@protocol(MGLMapSnapshotProtocol)]); + testCoordinates((id)snapshotOverlay); + + [expectation fulfill]; + } completionHandler:^(MGLMapSnapshot * _Nullable snapshot, NSError * _Nullable error) { + XCTAssert([snapshot conformsToProtocol:@protocol(MGLMapSnapshotProtocol)]); + testCoordinates((id)snapshot); + + [expectation fulfill]; + }]; + + [self waitForExpectations:@[expectation] timeout:10.0]; +} + + @end diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 20001c26a8..c873847b4f 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -528,6 +528,8 @@ CABE5DAD2072FAB40003AF3C /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA8847D21CBAF91600AB86E3 /* Mapbox.framework */; }; CAD9D0AA22A86D6F001B25EE /* MGLResourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */; }; CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */; }; + CAFB3C14234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */; }; + CAFB3C15234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */; }; CF75A91522D85E860058A5C4 /* MGLLoggingConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF75A91422D85E860058A5C4 /* MGLLoggingConfiguration.mm */; }; CF75A91622D85E860058A5C4 /* MGLLoggingConfiguration.mm in Sources */ = {isa = PBXBuildFile; fileRef = CF75A91422D85E860058A5C4 /* MGLLoggingConfiguration.mm */; }; DA00FC8E1D5EEB0D009AABC8 /* MGLAttributionInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -1072,8 +1074,8 @@ 5580B45A229570A10091291B /* MGLMapView+OpenGL.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "MGLMapView+OpenGL.mm"; sourceTree = ""; }; 558DE79E1E5615E400C7916D /* MGLFoundation_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLFoundation_Private.h; sourceTree = ""; }; 558DE79F1E5615E400C7916D /* MGLFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLFoundation.mm; sourceTree = ""; }; - 55CF752E213ED92000ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmbgl-vendor-icu.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 55CF7530213ED92A00ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libmbgl-vendor-icu.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 55CF752E213ED92000ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-vendor-icu.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 55CF7530213ED92A00ED86C4 /* libmbgl-vendor-icu.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-vendor-icu.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 55D120A71F791007004B6D81 /* libmbgl-loop-darwin.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-loop-darwin.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 55D120A91F79100C004B6D81 /* libmbgl-filesource.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libmbgl-filesource.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 55D8C9941D0F133500F42F10 /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = config.xcconfig; path = ../../build/ios/config.xcconfig; sourceTree = ""; }; @@ -1218,6 +1220,7 @@ CAD9D0A922A86D6F001B25EE /* MGLResourceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLResourceTests.mm; path = ../../darwin/test/MGLResourceTests.mm; sourceTree = ""; }; CAE7AD5320F46EF5003B6782 /* integration-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "integration-Bridging-Header.h"; sourceTree = ""; }; CAE7AD5420F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MGLMapSnapshotterSwiftTests.swift; sourceTree = ""; }; + CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter_Private.h; sourceTree = ""; }; CF75A91422D85E860058A5C4 /* MGLLoggingConfiguration.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLoggingConfiguration.mm; sourceTree = ""; }; DA00FC8C1D5EEB0D009AABC8 /* MGLAttributionInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAttributionInfo.h; sourceTree = ""; }; DA00FC8D1D5EEB0D009AABC8 /* MGLAttributionInfo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLAttributionInfo.mm; sourceTree = ""; }; @@ -2151,6 +2154,7 @@ DA8847E21CBAFA5100AB86E3 /* MGLMapCamera.h */, DA8848031CBAFA6200AB86E3 /* MGLMapCamera.mm */, 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */, + CAFB3C13234505D500399265 /* MGLMapSnapshotter_Private.h */, 927FBCFE1F4DB05500F8BF1F /* MGLMapSnapshotter.mm */, DD0902A41DB18F1B00C5BDCE /* MGLNetworkConfiguration.h */, 1F2B94BF221636D800210640 /* MGLNetworkConfiguration_Private.h */, @@ -2529,6 +2533,7 @@ 1F6A82A221360F9D00BA5B41 /* MGLLoggingConfiguration.h in Headers */, DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */, 967C864B210A9D3C004DF794 /* UIDevice+MGLAdditions.h in Headers */, + CAFB3C14234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */, 1FCAE2A220B872A400C577DD /* MGLLocationManager.h in Headers */, DACA86262019218600E9693A /* MGLRasterDEMSource.h in Headers */, 353933F81D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */, @@ -2722,6 +2727,7 @@ 35E1A4D91D74336F007AA97F /* MGLValueEvaluator.h in Headers */, DABFB8701CBE9A0F00D62B32 /* MGLMapView+IBAdditions.h in Headers */, 9C6E283822A982670056B7BE /* MMEEventLogger.h in Headers */, + CAFB3C15234505D500399265 /* MGLMapSnapshotter_Private.h in Headers */, 6F018BAF220031BF003E7269 /* UIView+MGLAdditions.h in Headers */, 96E516EA2000560B00A02306 /* MGLAnnotationView_Private.h in Headers */, 96E516FB20005A4000A02306 /* MGLUserLocationHeadingBeamLayer.h in Headers */, diff --git a/platform/ios/sdk-files.json b/platform/ios/sdk-files.json index 0df4b381ba..dc59e179c8 100644 --- a/platform/ios/sdk-files.json +++ b/platform/ios/sdk-files.json @@ -243,6 +243,7 @@ "MMEDate.h": "platform/ios/vendor/mapbox-events-ios/MapboxMobileEvents/MMEDate.h", "NSString+MGLAdditions.h": "platform/darwin/src/NSString+MGLAdditions.h", "UIDevice+MGLAdditions.h": "platform/ios/src/UIDevice+MGLAdditions.h", + "MGLMapSnapshotter_Private.h": "platform/darwin/src/MGLMapSnapshotter_Private.h", "MGLRendererFrontend.h": "platform/darwin/src/MGLRendererFrontend.h", "MGLStyleValue_Private.h": "platform/darwin/src/MGLStyleValue_Private.h", "MGLFillExtrusionStyleLayer_Private.h": "platform/darwin/src/MGLFillExtrusionStyleLayer_Private.h", -- cgit v1.2.1 From 5c565a5e51be8379ddc2ffb5c859d8cfebe2fcd5 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Fri, 4 Oct 2019 17:13:00 -0700 Subject: [ios] Fixes an issue that caused the ornaments ignore contentInset property. (#15584) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ios] Add mapView content inset tests. * [ios] Fix an issue that caused the ornaments ignore the contentInsets. Fixed an issue that caused ornaments ignore the contentInset. Added a new property automaticallyAdjustContentInset that has the same purpose as UIViewController. automaticallyAdjustsScrollViewInsets. This was changed due to the latter being deprecated. * [ios] Fix automaticallyAdjustsScrollViewInsets legacy behavior. The property automaticallyAdjustsScrollViewInsets overrode automaticallyAdjustsScrollViewInsets which caused a breaking change. This is fixed to consider the legacy property when calculating the content insets and added tests for both cases. * [ios] Fix the contentInset value after adding padding to the camera. Fixed an issue that caused a discrepancy between the contentInset in MGLMapView and the padding in the transformation state. When padding is passed through methods such as setCamera it’s persisted. This fix resets the contentInsets. * [ios] Fix pinch test. * [ios] Update automaticallyAdjustsScrollViewInsets name and documentation. * [ios] Update changelog. --- platform/ios/CHANGELOG.md | 3 + platform/ios/ios.xcodeproj/project.pbxproj | 8 + platform/ios/src/MGLMapView.h | 22 +- platform/ios/src/MGLMapView.mm | 148 ++++++++--- platform/ios/test/MGLMapViewContentInsetTests.m | 177 +++++++++++++ .../ios/test/MGLMapViewGestureRecognizerTests.mm | 280 +++++++++++++++++++++ platform/ios/test/MGLMapViewPitchTests.m | 4 + platform/ios/test/MGLMockGestureRecognizers.h | 19 ++ platform/ios/test/MGLMockGestureRecognizers.m | 44 ++++ 9 files changed, 670 insertions(+), 35 deletions(-) create mode 100644 platform/ios/test/MGLMapViewContentInsetTests.m create mode 100644 platform/ios/test/MGLMapViewGestureRecognizerTests.mm diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index d11c9a5f95..a3c4546276 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -14,6 +14,9 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Added `-[MGLMapSnapshotOverlay coordinateForPoint:]` and `-[MGLMapSnapshotOverlay pointForCoordinate:]` to convert between context and map coordinates, mirroring those of `MGLMapSnapshot`. ([#15746](https://github.com/mapbox/mapbox-gl-native/pull/15746)) * Suppress network requests for expired tiles update, if these tiles are invisible. ([#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741)) +* Fixed an issue that cause the ornaments to ignore `MGLMapView.contentInset` property. ([#15584](https://github.com/mapbox/mapbox-gl-native/pull/15584)) +* Fixed an issue that cause `-[MGLMapView setCamere:withDuration:animationTimingFunction:edgePadding:completionHandler:]` persist the value of `edgePadding`. ([#15584](https://github.com/mapbox/mapbox-gl-native/pull/15584)) +* Added `MGLMapView.automaticallyAdjustsContentInset` property that indicates if wether the map view should automatically adjust its content insets. ([#15584](https://github.com/mapbox/mapbox-gl-native/pull/15584)) * Fixed an issue that caused `MGLScaleBar` to have an incorrect size when resizing or rotating. ([#15703](https://github.com/mapbox/mapbox-gl-native/pull/15703)) ## 5.4.0 - September 25, 2019 diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index c873847b4f..350a8014fd 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 170C437D2029D97900863DF0 /* MGLHeatmapStyleLayerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 170C43792028D49800863DF0 /* MGLHeatmapStyleLayerTests.mm */; }; 1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; }; 1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; }; + 1F0196AA23174B0700F5C819 /* MGLMapViewContentInsetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F0196A923174B0700F5C819 /* MGLMapViewContentInsetTests.m */; }; 1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1F06668D1EC64F8E001C16D7 /* MGLLight.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F0666891EC64F8E001C16D7 /* MGLLight.mm */; }; 1F26B6C120E189C9007BCC21 /* MBXCustomLocationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F26B6C020E189C9007BCC21 /* MBXCustomLocationViewController.m */; }; @@ -50,6 +51,7 @@ 1F7454A91ED08AB400021D39 /* MGLLightTest.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F7454A61ED08AB400021D39 /* MGLLightTest.mm */; }; 1F8A59F72165326D004DFE75 /* sideload_sat.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F8A59F62165326C004DFE75 /* sideload_sat.db */; }; 1F8A59F821653275004DFE75 /* sideload_sat.db in Resources */ = {isa = PBXBuildFile; fileRef = 1F8A59F62165326C004DFE75 /* sideload_sat.db */; }; + 1F8E8A81233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F8E8A80233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm */; }; 1F95931D1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */; }; 1FC4817D2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */; }; 1FC4817F2098CD80000D09B4 /* NSPredicate+MGLPrivateAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */; }; @@ -899,6 +901,7 @@ 170C43782028D49800863DF0 /* MGLHeatmapColorTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLHeatmapColorTests.mm; path = ../../darwin/test/MGLHeatmapColorTests.mm; sourceTree = ""; }; 170C43792028D49800863DF0 /* MGLHeatmapStyleLayerTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLHeatmapStyleLayerTests.mm; path = ../../darwin/test/MGLHeatmapStyleLayerTests.mm; sourceTree = ""; }; 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = ""; }; + 1F0196A923174B0700F5C819 /* MGLMapViewContentInsetTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewContentInsetTests.m; sourceTree = ""; }; 1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = ""; }; 1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = ""; }; 1F26B6BF20E189C9007BCC21 /* MBXCustomLocationViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MBXCustomLocationViewController.h; sourceTree = ""; }; @@ -910,6 +913,7 @@ 1F7454941ECD450D00021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = ""; }; 1F7454A61ED08AB400021D39 /* MGLLightTest.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLLightTest.mm; path = ../../darwin/test/MGLLightTest.mm; sourceTree = ""; }; 1F8A59F62165326C004DFE75 /* sideload_sat.db */ = {isa = PBXFileReference; lastKnownFileType = file; name = sideload_sat.db; path = ../../../test/fixtures/offline_database/sideload_sat.db; sourceTree = ""; }; + 1F8E8A80233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapViewGestureRecognizerTests.mm; sourceTree = ""; }; 1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLNSDateAdditionsTests.mm; path = ../../darwin/test/MGLNSDateAdditionsTests.mm; sourceTree = ""; }; 1FC4817B2098CBC0000D09B4 /* NSPredicate+MGLPrivateAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSPredicate+MGLPrivateAdditions.h"; sourceTree = ""; }; 1FCAE2A020B872A400C577DD /* MGLLocationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLLocationManager.h; sourceTree = ""; }; @@ -2084,7 +2088,9 @@ DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */, DA695425215B1E75002041A4 /* MGLMapCameraTests.m */, 96E6145522CC135200109F14 /* MGLMapViewCompassViewTests.mm */, + 1F0196A923174B0700F5C819 /* MGLMapViewContentInsetTests.m */, 96ED34DD22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm */, + 1F8E8A80233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm */, 16376B481FFEED010000563E /* MGLMapViewLayoutTests.m */, 96381C0122C6F3950053497D /* MGLMapViewPitchTests.m */, 9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */, @@ -3322,11 +3328,13 @@ 920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */, DA5DB12A1FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m in Sources */, 96ED34DE22374C0900E9FCA9 /* MGLMapViewDirectionTests.mm in Sources */, + 1F0196AA23174B0700F5C819 /* MGLMapViewContentInsetTests.m in Sources */, FAE1CDCB1E9D79CB00C40B5B /* MGLFillExtrusionStyleLayerTests.mm in Sources */, DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */, 357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */, 3502D6CC22AE88D5006BDFCE /* MGLAccountManagerTests.m in Sources */, DAF25720201902BC00367EF5 /* MGLHillshadeStyleLayerTests.mm in Sources */, + 1F8E8A81233A9FD9009B51ED /* MGLMapViewGestureRecognizerTests.mm in Sources */, 353D23961D0B0DFE002BE09D /* MGLAnnotationViewTests.m in Sources */, DA0CD5901CF56F6A00A5F5A5 /* MGLFeatureTests.mm in Sources */, 556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */, diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 017ba525c4..8f27adee9e 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -286,6 +286,17 @@ MGL_EXPORT */ - (IBAction)reloadStyle:(nullable id)sender; +/** + A boolean value that indicates if whether the map view should automatically + adjust its content insets. + + When this property is set to `YES` the map automatically updates its + `contentInset` property to account for any area not covered by navigation bars, + tab bars, toolbars, and other ancestors that obscure the map view. + + */ +@property (assign) BOOL automaticallyAdjustsContentInset; + /** A Boolean value indicating whether the map may display scale information. @@ -1308,10 +1319,13 @@ MGL_EXPORT view’s frame. Otherwise, those properties are inset, excluding part of the frame from the viewport. For instance, if the only the top edge is inset, the map center is effectively shifted downward. - + When the map view’s superview is an instance of `UIViewController` whose `automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this property may be overridden at any time. + + The usage of `automaticallyAdjustsScrollViewInsets` has been deprecated + use the map view’s property `MGLMapView.automaticallyAdjustsContentInset`instead. Changing the value of this property updates the map view immediately. If you want to animate the change, use the `-setContentInset:animated:completionHandler:` @@ -1333,6 +1347,9 @@ MGL_EXPORT `automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this property may be overridden at any time. + The usage of `automaticallyAdjustsScrollViewInsets` has been deprecated + use the map view’s property `MGLMapView.automaticallyAdjustsContentInset`instead. + To specify a completion handler to execute after the animation finishes, use the `-setContentInset:animated:completionHandler:` method. @@ -1357,6 +1374,9 @@ MGL_EXPORT When the map view’s superview is an instance of `UIViewController` whose `automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this property may be overridden at any time. + + The usage of `automaticallyAdjustsScrollViewInsets` has been deprecated + use the map view’s property `MGLMapView.automaticallyAdjustsContentInset`instead. @param contentInset The new values to inset the content by. @param animated Specify `YES` if you want the map view to animate the change to diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 76cec479bb..9b4ef8ff2d 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -274,6 +274,11 @@ public: /// Tilt gesture recognizer helper @property (nonatomic, assign) CGPoint dragGestureMiddlePoint; +/// This property is used to keep track of the view's safe edge insets +/// and calculate the ornament's position +@property (nonatomic, assign) UIEdgeInsets safeMapViewContentInsets; +@property (nonatomic, strong) NSNumber *automaticallyAdjustContentInsetHolder; + - (mbgl::Map &)mbglMap; @end @@ -518,6 +523,14 @@ public: _annotationViewReuseQueueByIdentifier = [NSMutableDictionary dictionary]; _selectedAnnotationTag = MGLAnnotationTagNotFound; _annotationsNearbyLastTap = {}; + + // TODO: This warning should be removed when automaticallyAdjustsScrollViewInsets is removed from + // the UIViewController api. + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSLog(@"%@ WARNING UIViewController.automaticallyAdjustsScrollViewInsets is deprecated use MGLMapView.automaticallyAdjustContentInset instead.", + NSStringFromClass(self.class)); + }); // setup logo // @@ -832,23 +845,46 @@ public: size:(CGSize)size margins:(CGPoint)margins { NSMutableArray *updatedConstraints = [NSMutableArray array]; + UIEdgeInsets inset = UIEdgeInsetsZero; + + BOOL automaticallyAdjustContentInset; + if (_automaticallyAdjustContentInsetHolder) { + automaticallyAdjustContentInset = _automaticallyAdjustContentInsetHolder.boolValue; + } else { + UIViewController *viewController = [self rootViewController]; + automaticallyAdjustContentInset = viewController.automaticallyAdjustsScrollViewInsets; + } + + if (! automaticallyAdjustContentInset) { + inset = UIEdgeInsetsMake(self.contentInset.top - self.safeMapViewContentInsets.top, + self.contentInset.left - self.safeMapViewContentInsets.left, + self.contentInset.bottom - self.safeMapViewContentInsets.bottom, + self.contentInset.right - self.safeMapViewContentInsets.right); + + // makes sure the insets don't have negative values that could hide the ornaments + // thus violating our ToS + inset = UIEdgeInsetsMake(fmaxf(inset.top, 0), + fmaxf(inset.left, 0), + fmaxf(inset.bottom, 0), + fmaxf(inset.right, 0)); + } switch (position) { case MGLOrnamentPositionTopLeft: - [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y]]; - [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x]]; + [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y + inset.top]]; + [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x + inset.left]]; break; case MGLOrnamentPositionTopRight: - [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y]]; - [updatedConstraints addObject:[self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x]]; + [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y + inset.top]]; + [updatedConstraints addObject:[self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x + inset.right]]; break; case MGLOrnamentPositionBottomLeft: - [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y]]; - [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x]]; + [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y + inset.bottom]]; + [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x + inset.left]]; break; case MGLOrnamentPositionBottomRight: - [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y]]; - [updatedConstraints addObject: [self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x]]; + [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y + inset.bottom]]; + [updatedConstraints addObject: [self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x + inset.right]]; break; } @@ -968,6 +1004,38 @@ public: /// Updates `contentInset` to reflect the current window geometry. - (void)adjustContentInset { + UIEdgeInsets adjustedContentInsets = UIEdgeInsetsZero; + UIViewController *viewController = [self rootViewController]; + BOOL automaticallyAdjustContentInset; + if (@available(iOS 11.0, *)) + { + adjustedContentInsets = self.safeAreaInsets; + + } else { + adjustedContentInsets.top = viewController.topLayoutGuide.length; + CGFloat bottomPoint = CGRectGetMaxY(viewController.view.bounds) - + (CGRectGetMaxY(viewController.view.bounds) + - viewController.bottomLayoutGuide.length); + adjustedContentInsets.bottom = bottomPoint; + + } + + if (_automaticallyAdjustContentInsetHolder) { + automaticallyAdjustContentInset = _automaticallyAdjustContentInsetHolder.boolValue; + } else { + automaticallyAdjustContentInset = viewController.automaticallyAdjustsScrollViewInsets; + } + + self.safeMapViewContentInsets = adjustedContentInsets; + if ( ! automaticallyAdjustContentInset) + { + return; + } + + self.contentInset = adjustedContentInsets; +} + +- (UIViewController *)rootViewController { // We could crawl all the way up the responder chain using // -viewControllerForLayoutGuides, but an intervening view means that any // manual contentInset should not be overridden; something other than the @@ -983,25 +1051,16 @@ public: // This map view is an immediate child of a view controller’s content view. viewController = (UIViewController *)self.superview.nextResponder; } + return viewController; +} - if ( ! viewController.automaticallyAdjustsScrollViewInsets) - { - return; - } - - UIEdgeInsets contentInset = UIEdgeInsetsZero; - CGPoint topPoint = CGPointMake(0, viewController.topLayoutGuide.length); - contentInset.top = [self convertPoint:topPoint fromView:viewController.view].y; - CGPoint bottomPoint = CGPointMake(0, CGRectGetMaxY(viewController.view.bounds) - - viewController.bottomLayoutGuide.length); - contentInset.bottom = (CGRectGetMaxY(self.bounds) - - [self convertPoint:bottomPoint fromView:viewController.view].y); - - // Negative insets are invalid, replace with 0. - contentInset.top = fmaxf(contentInset.top, 0); - contentInset.bottom = fmaxf(contentInset.bottom, 0); +- (void)setAutomaticallyAdjustsContentInset:(BOOL)automaticallyAdjustsContentInset { + MGLLogDebug(@"Setting automaticallyAdjustsContentInset: %@", MGLStringFromBOOL(automaticallyAdjustsContentInset)); + _automaticallyAdjustContentInsetHolder = [NSNumber numberWithBool:automaticallyAdjustsContentInset]; +} - self.contentInset = contentInset; +- (BOOL)automaticallyAdjustsContentInset { + return _automaticallyAdjustContentInsetHolder.boolValue; } - (void)setContentInset:(UIEdgeInsets)contentInset @@ -1701,7 +1760,10 @@ public: if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera]) { - self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })); + self.mbglMap.jumpTo(mbgl::CameraOptions() + .withZoom(newZoom) + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset))); // The gesture recognizer only reports the gesture’s current center // point, so use the previous center point to anchor the transition. @@ -1759,7 +1821,10 @@ public: { if (drift) { - self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(zoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }), MGLDurationFromTimeInterval(duration)); + self.mbglMap.easeTo(mbgl::CameraOptions() + .withZoom(zoom) + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(duration)); } } @@ -1824,7 +1889,8 @@ public: { self.mbglMap.jumpTo(mbgl::CameraOptions() .withBearing(newDegrees) - .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y})); + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset))); } [self cameraIsChanging]; @@ -1865,7 +1931,8 @@ public: { self.mbglMap.easeTo(mbgl::CameraOptions() .withBearing(newDegrees) - .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }), + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(decelerationRate)); [self notifyGestureDidEndWithDrift:YES]; @@ -1993,7 +2060,10 @@ public: if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera]) { mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y); - self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(center), MGLDurationFromTimeInterval(MGLAnimationDuration)); + self.mbglMap.easeTo(mbgl::CameraOptions() + .withZoom(newZoom) + .withAnchor(center) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(MGLAnimationDuration)); __weak MGLMapView *weakSelf = self; @@ -2031,7 +2101,10 @@ public: if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera]) { mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y); - self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(center), MGLDurationFromTimeInterval(MGLAnimationDuration)); + self.mbglMap.easeTo(mbgl::CameraOptions() + .withZoom(newZoom) + .withAnchor(center) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(MGLAnimationDuration)); __weak MGLMapView *weakSelf = self; @@ -2073,7 +2146,10 @@ public: if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera]) { - self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })); + self.mbglMap.jumpTo(mbgl::CameraOptions() + .withZoom(newZoom) + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset))); } [self cameraIsChanging]; @@ -2140,7 +2216,8 @@ public: { self.mbglMap.jumpTo(mbgl::CameraOptions() .withPitch(pitchNew) - .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })); + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset))); } [self cameraIsChanging]; @@ -3200,7 +3277,10 @@ public: centerPoint = self.userLocationAnnotationViewCenter; } double newZoom = round(self.zoomLevel) + log2(scaleFactor); - self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })); + self.mbglMap.jumpTo(mbgl::CameraOptions() + .withZoom(newZoom) + .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }) + .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset))); [self unrotateIfNeededForGesture]; _accessibilityValueAnnouncementIsPending = YES; diff --git a/platform/ios/test/MGLMapViewContentInsetTests.m b/platform/ios/test/MGLMapViewContentInsetTests.m new file mode 100644 index 0000000000..185baf4a05 --- /dev/null +++ b/platform/ios/test/MGLMapViewContentInsetTests.m @@ -0,0 +1,177 @@ +#import +#import + +@interface MGLMapViewContentInsetTests : XCTestCase + +@property (nonatomic) MGLMapView *mapView; +@property (nonatomic) UIWindow *window; +@property (nonatomic) UIViewController *viewController; +@property (nonatomic) XCTestExpectation *styleLoadingExpectation; +@property (assign) CGRect screenBounds; + +@end + +@implementation MGLMapViewContentInsetTests + +- (void)setUp { + [super setUp]; + + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; + NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + self.screenBounds = UIScreen.mainScreen.bounds; + self.mapView = [[MGLMapView alloc] initWithFrame:self.screenBounds styleURL:styleURL]; + self.mapView.zoomLevel = 16; + self.mapView.delegate = self; + + self.viewController = [[UIViewController alloc] init]; + self.viewController.view = [[UIView alloc] initWithFrame:self.screenBounds]; + [self.viewController.view addSubview:self.mapView]; + self.window = [[UIWindow alloc] initWithFrame:self.screenBounds]; + [self.window addSubview:self.viewController.view]; + [self.window makeKeyAndVisible]; + + if (!self.mapView.style) { + _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; + [self waitForExpectationsWithTimeout:10 handler:nil]; + } +} + +- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { + XCTAssertNotNil(mapView.style); + XCTAssertEqual(mapView.style, style); + + [_styleLoadingExpectation fulfill]; +} + +- (void)tearDown { + self.mapView = nil; + [MGLAccountManager setAccessToken:nil]; + [super tearDown]; +} + +- (void)testContentInsetCenter { + CLLocationCoordinate2D center = CLLocationCoordinate2DMake(1.0, 5.0); + self.mapView.centerCoordinate = center; + XCTAssertEqualWithAccuracy(self.mapView.centerCoordinate.latitude, center.latitude, 0.01); + XCTAssertEqualWithAccuracy(self.mapView.centerCoordinate.longitude, center.longitude, 0.01); + + CGPoint centerPoint = [self.mapView convertCoordinate:center toPointToView:self.mapView]; + + XCTAssertEqualWithAccuracy(centerPoint.x, self.screenBounds.size.width/2, 0.01); + XCTAssertEqualWithAccuracy(centerPoint.y, self.screenBounds.size.height/2, 0.01); + + // shifting contentInset should keep the same centerCoordinate but shift the screen + // center point accordingly + UIEdgeInsets contentInset = UIEdgeInsetsMake(50.0, 10.0, 10.0, 30.0); + self.mapView.contentInset = contentInset; + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + XCTAssertEqualWithAccuracy(self.mapView.centerCoordinate.latitude, center.latitude, 0.01); + XCTAssertEqualWithAccuracy(self.mapView.centerCoordinate.longitude, center.longitude, 0.01); + CGPoint shiftedPoint = [self.mapView convertCoordinate:center toPointToView:self.mapView]; + CGPoint expectedShiftedPoint = CGPointMake((self.screenBounds.size.width/2) + ((contentInset.left - contentInset.right) / 2 ), + (self.screenBounds.size.height/2) + ((contentInset.top - contentInset.bottom) / 2)); + XCTAssertEqualWithAccuracy(shiftedPoint.x, expectedShiftedPoint.x, 0.01); + XCTAssertEqualWithAccuracy(shiftedPoint.y, expectedShiftedPoint.y, 0.01); + + +} + +- (void)testContentInsetOrnaments { + CGFloat margin = 8; + self.mapView.contentInset = UIEdgeInsetsZero; + UIView *scaleBar = self.mapView.scaleBar; + CGPoint expectedScaleBarOrigin = CGPointMake(margin, margin); + XCTAssertTrue(CGPointEqualToPoint(scaleBar.frame.origin, expectedScaleBarOrigin)); + + UIView *compassView = self.mapView.compassView; + CGFloat x = self.screenBounds.size.width - compassView.bounds.size.width - margin; + CGPoint expectedCompassOrigin = CGPointMake(x, margin); + XCTAssertTrue(CGPointEqualToPoint(compassView.frame.origin, expectedCompassOrigin)); + + UIView *logoView = self.mapView.logoView; + CGFloat y = self.screenBounds.size.height - logoView.bounds.size.height - margin; + CGPoint expectedLogoOrigin = CGPointMake(margin, y); + XCTAssertTrue(CGPointEqualToPoint(logoView.frame.origin, expectedLogoOrigin)); + + UIView *attributionView = self.mapView.attributionButton; + x = self.screenBounds.size.width - attributionView.bounds.size.width - margin; + y = self.screenBounds.size.height - attributionView.bounds.size.height - margin; + CGPoint expectedAttributionOrigin = CGPointMake(x, y); + XCTAssertTrue(CGPointEqualToPoint(attributionView.frame.origin, expectedAttributionOrigin)); + + UIEdgeInsets insets = UIEdgeInsetsMake(15, 10, 20, 5); + self.viewController.automaticallyAdjustsScrollViewInsets = NO; + self.mapView.contentInset = insets; + + [self.mapView setNeedsLayout]; + [self.mapView layoutIfNeeded]; + + expectedScaleBarOrigin = CGPointMake(insets.left + self.mapView.scaleBarMargins.x, insets.top + self.mapView.scaleBarMargins.y); + XCTAssertTrue(CGPointEqualToPoint(scaleBar.frame.origin, expectedScaleBarOrigin)); + + x = self.screenBounds.size.width - compassView.bounds.size.width - insets.right - self.mapView.compassViewMargins.x; + expectedCompassOrigin = CGPointMake(x, insets.top + self.mapView.compassViewMargins.y); + XCTAssertTrue(CGPointEqualToPoint(compassView.frame.origin, expectedCompassOrigin)); + + y = self.screenBounds.size.height - logoView.bounds.size.height - insets.bottom - self.mapView.logoViewMargins.y; + expectedLogoOrigin = CGPointMake(insets.left + self.mapView.logoViewMargins.x, y); + XCTAssertTrue(CGPointEqualToPoint(logoView.frame.origin, expectedLogoOrigin)); + + x = self.screenBounds.size.width - attributionView.bounds.size.width - insets.right - self.mapView.attributionButtonMargins.x; + y = self.screenBounds.size.height - attributionView.bounds.size.height - insets.bottom - self.mapView.attributionButtonMargins.y; + expectedAttributionOrigin = CGPointMake(x, y); + XCTAssertTrue(CGPointEqualToPoint(attributionView.frame.origin, expectedAttributionOrigin)); + + // tests that passing negative values result in a 0 inset value + insets = UIEdgeInsetsMake(-100, -100, -100, -100); + self.mapView.contentInset = insets; + + [self.mapView setNeedsLayout]; + [self.mapView layoutIfNeeded]; + + expectedScaleBarOrigin = CGPointMake(margin, margin); + XCTAssertTrue(CGPointEqualToPoint(scaleBar.frame.origin, expectedScaleBarOrigin)); + + x = self.screenBounds.size.width - compassView.bounds.size.width - margin; + expectedCompassOrigin = CGPointMake(x, margin); + XCTAssertTrue(CGPointEqualToPoint(compassView.frame.origin, expectedCompassOrigin)); + + y = self.screenBounds.size.height - logoView.bounds.size.height - margin; + expectedLogoOrigin = CGPointMake(margin, y); + XCTAssertTrue(CGPointEqualToPoint(logoView.frame.origin, expectedLogoOrigin)); + + x = self.screenBounds.size.width - attributionView.bounds.size.width - margin; + y = self.screenBounds.size.height - attributionView.bounds.size.height - margin; + expectedAttributionOrigin = CGPointMake(x, y); + XCTAssertTrue(CGPointEqualToPoint(attributionView.frame.origin, expectedAttributionOrigin)); + + self.mapView.automaticallyAdjustsContentInset = YES; + insets = UIEdgeInsetsMake(100, 100, 100, 100); + self.mapView.contentInset = insets; + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, insets)); + + [self.mapView setNeedsLayout]; + [self.mapView layoutIfNeeded]; + + // when automaticallyAdjustsContentInset = YES the content insets should be overwriten + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, insets)); + + expectedScaleBarOrigin = CGPointMake(margin, margin); + XCTAssertTrue(CGPointEqualToPoint(scaleBar.frame.origin, expectedScaleBarOrigin)); + + x = self.screenBounds.size.width - compassView.bounds.size.width - margin; + expectedCompassOrigin = CGPointMake(x, margin); + XCTAssertTrue(CGPointEqualToPoint(compassView.frame.origin, expectedCompassOrigin)); + + y = self.screenBounds.size.height - logoView.bounds.size.height - margin; + expectedLogoOrigin = CGPointMake(margin, y); + XCTAssertTrue(CGPointEqualToPoint(logoView.frame.origin, expectedLogoOrigin)); + + x = self.screenBounds.size.width - attributionView.bounds.size.width - margin; + y = self.screenBounds.size.height - attributionView.bounds.size.height - margin; + expectedAttributionOrigin = CGPointMake(x, y); + XCTAssertTrue(CGPointEqualToPoint(attributionView.frame.origin, expectedAttributionOrigin)); + +} + +@end diff --git a/platform/ios/test/MGLMapViewGestureRecognizerTests.mm b/platform/ios/test/MGLMapViewGestureRecognizerTests.mm new file mode 100644 index 0000000000..58fbf2d03b --- /dev/null +++ b/platform/ios/test/MGLMapViewGestureRecognizerTests.mm @@ -0,0 +1,280 @@ +#import +#import + +#import "../../darwin/src/MGLGeometry_Private.h" +#import "MGLMockGestureRecognizers.h" + +#include +#include + +@interface MGLMapView (MGLMapViewGestureRecognizerTests) + +- (mbgl::Map &)mbglMap; + +- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch; +- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate; +- (void)handleDoubleTapGesture:(UITapGestureRecognizer *)doubleTap; +- (void)handleTwoFingerTapGesture:(UITapGestureRecognizer *)twoFingerTap; +- (void)handleQuickZoomGesture:(UILongPressGestureRecognizer *)quickZoom; +- (void)handleTwoFingerDragGesture:(UIPanGestureRecognizer *)twoFingerDrag; + +@end + +@interface MGLMapViewGestureRecognizerTests : XCTestCase + +@property (nonatomic) MGLMapView *mapView; +@property (nonatomic) UIWindow *window; +@property (nonatomic) UIViewController *viewController; +@property (nonatomic) XCTestExpectation *styleLoadingExpectation; +@property (nonatomic) XCTestExpectation *twoFingerExpectation; +@property (nonatomic) XCTestExpectation *quickZoomExpectation; +@property (nonatomic) XCTestExpectation *doubleTapExpectation; +@property (nonatomic) XCTestExpectation *twoFingerDragExpectation; +@property (assign) CGRect screenBounds; + +@end + +@implementation MGLMapViewGestureRecognizerTests + +- (void)setUp { + [super setUp]; + + [MGLAccountManager setAccessToken:@"pk.feedcafedeadbeefbadebede"]; + NSURL *styleURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"one-liner" withExtension:@"json"]; + self.screenBounds = UIScreen.mainScreen.bounds; + self.mapView = [[MGLMapView alloc] initWithFrame:self.screenBounds styleURL:styleURL]; + self.mapView.zoomLevel = 16; + self.mapView.delegate = self; + + self.viewController = [[UIViewController alloc] init]; + self.viewController.view = [[UIView alloc] initWithFrame:self.screenBounds]; + [self.viewController.view addSubview:self.mapView]; + self.window = [[UIWindow alloc] initWithFrame:self.screenBounds]; + [self.window addSubview:self.viewController.view]; + [self.window makeKeyAndVisible]; + + if (!self.mapView.style) { + _styleLoadingExpectation = [self expectationWithDescription:@"Map view should finish loading style."]; + [self waitForExpectationsWithTimeout:10 handler:nil]; + } +} + +- (void)mapView:(MGLMapView *)mapView didFinishLoadingStyle:(MGLStyle *)style { + XCTAssertNotNil(mapView.style); + XCTAssertEqual(mapView.style, style); + + [_styleLoadingExpectation fulfill]; +} + +- (void)testHandlePinchGestureContentInset { + UIEdgeInsets contentInset = UIEdgeInsetsZero; + self.mapView.contentInset = contentInset; + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset); + auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding."); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + contentInset = UIEdgeInsetsMake(20, 20, 20, 20); + [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil]; + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertNotEqual(padding, cameraPadding); + + UIPinchGestureRecognizerMock *pinchGesture = [[UIPinchGestureRecognizerMock alloc] initWithTarget:nil action:nil]; + pinchGesture.state = UIGestureRecognizerStateBegan; + pinchGesture.scale = 1.0; + [self.mapView handlePinchGesture:pinchGesture]; + XCTAssertNotEqual(padding, cameraPadding); + + pinchGesture.state = UIGestureRecognizerStateChanged; + [self.mapView handlePinchGesture:pinchGesture]; + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + + pinchGesture.state = UIGestureRecognizerStateEnded; + [self.mapView handlePinchGesture:pinchGesture]; + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + +} + +- (void)testHandleRotateGestureContentInset { + UIEdgeInsets contentInset = UIEdgeInsetsZero; + self.mapView.contentInset = contentInset; + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset); + auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding."); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + contentInset = UIEdgeInsetsMake(20, 20, 20, 20); + [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil]; + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertNotEqual(padding, cameraPadding); + + UIRotationGestureRecognizerMock *rotateGesture = [[UIRotationGestureRecognizerMock alloc] initWithTarget:nil action:nil]; + rotateGesture.state = UIGestureRecognizerStateBegan; + rotateGesture.rotation = 1; + [self.mapView handleRotateGesture:rotateGesture]; + XCTAssertNotEqual(padding, cameraPadding); + + rotateGesture.state = UIGestureRecognizerStateChanged; + [self.mapView handleRotateGesture:rotateGesture]; + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + + rotateGesture.state = UIGestureRecognizerStateEnded; + [self.mapView handleRotateGesture:rotateGesture]; + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + +} + +- (void)testHandleDoubleTapGestureContentInset { + UIEdgeInsets contentInset = UIEdgeInsetsMake(1, 1, 1, 1); + self.mapView.contentInset = contentInset; + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset); + auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding."); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + contentInset = UIEdgeInsetsMake(20, 20, 20, 20); + [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil]; + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertNotEqual(padding, cameraPadding); + + UITapGestureRecognizerMock *doubleTapGesture = [[UITapGestureRecognizerMock alloc] initWithTarget:nil action:nil]; + doubleTapGesture.mockTappedView = self.mapView; + doubleTapGesture.mockTappedPoint = CGPointMake(1.0, 1.0); + + [self.mapView handleDoubleTapGesture:doubleTapGesture]; + _doubleTapExpectation = [self expectationWithDescription:@"Double tap gesture animation."]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self->_doubleTapExpectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10 handler:nil]; + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + +} + +- (void)testHandleTwoFingerTapGesture { + UIEdgeInsets contentInset = UIEdgeInsetsZero; + self.mapView.contentInset = contentInset; + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset); + auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding."); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + contentInset = UIEdgeInsetsMake(20, 20, 20, 20); + [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil]; + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertNotEqual(padding, cameraPadding); + + UITapGestureRecognizerMock *twoFingerTap = [[UITapGestureRecognizerMock alloc] initWithTarget:nil action:nil]; + twoFingerTap.mockTappedView = self.mapView; + twoFingerTap.mockTappedPoint = CGPointMake(1.0, 1.0); + + [self.mapView handleTwoFingerTapGesture:twoFingerTap]; + _twoFingerExpectation = [self expectationWithDescription:@"Two Finger tap gesture animation."]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self->_twoFingerExpectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10 handler:nil]; + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); +} + +- (void)testHandleQuickZoomGesture { + UIEdgeInsets contentInset = UIEdgeInsetsZero; + self.mapView.contentInset = contentInset; + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset); + auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding."); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + contentInset = UIEdgeInsetsMake(20, 20, 20, 20); + [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil]; + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertNotEqual(padding, cameraPadding); + + UILongPressGestureRecognizerMock *quickZoom = [[UILongPressGestureRecognizerMock alloc] initWithTarget:nil action:nil]; + quickZoom.state = UIGestureRecognizerStateBegan; + [self.mapView handleQuickZoomGesture:quickZoom]; + XCTAssertNotEqual(padding, cameraPadding); + + quickZoom.state = UIGestureRecognizerStateChanged; + quickZoom.mockTappedPoint = CGPointMake(self.mapView.frame.size.width / 2, self.mapView.frame.size.height / 2); + [self.mapView handleQuickZoomGesture:quickZoom]; + _quickZoomExpectation = [self expectationWithDescription:@"Quick zoom gesture animation."]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self->_quickZoomExpectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10 handler:nil]; + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + + quickZoom.state = UIGestureRecognizerStateEnded; + [self.mapView handleQuickZoomGesture:quickZoom]; + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); +} + +- (void)testHandleTwoFingerDragGesture { + UIEdgeInsets contentInset = UIEdgeInsetsZero; + self.mapView.contentInset = contentInset; + mbgl::EdgeInsets padding = MGLEdgeInsetsFromNSEdgeInsets(self.mapView.contentInset); + auto cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"MGLMapView's contentInset property should match camera's padding."); + XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + contentInset = UIEdgeInsetsMake(20, 20, 20, 20); + [self.mapView setCamera:self.mapView.camera withDuration:0.1 animationTimingFunction:nil edgePadding:contentInset completionHandler:nil]; + XCTAssertFalse(UIEdgeInsetsEqualToEdgeInsets(self.mapView.contentInset, contentInset)); + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertNotEqual(padding, cameraPadding); + + UIPanGestureRecognizerMock *twoFingerDrag = [[UIPanGestureRecognizerMock alloc] initWithTarget:nil action:nil]; + twoFingerDrag.state = UIGestureRecognizerStateBegan; + twoFingerDrag.firstFingerPoint = CGPointMake(self.mapView.frame.size.width / 3, self.mapView.frame.size.height/2); + twoFingerDrag.secondFingerPoint = CGPointMake((self.mapView.frame.size.width / 2), self.mapView.frame.size.height/2); + twoFingerDrag.numberOfTouches = 2; + [self.mapView handleTwoFingerDragGesture:twoFingerDrag]; + XCTAssertNotEqual(padding, cameraPadding); + + twoFingerDrag.state = UIGestureRecognizerStateChanged; + twoFingerDrag.firstFingerPoint = CGPointMake(self.mapView.frame.size.width / 3, (self.mapView.frame.size.height/2)-10); + twoFingerDrag.secondFingerPoint = CGPointMake((self.mapView.frame.size.width / 2), (self.mapView.frame.size.height/2)-10); + [self.mapView handleTwoFingerDragGesture:twoFingerDrag]; + _twoFingerDragExpectation = [self expectationWithDescription:@"Quick zoom gesture animation."]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + [self->_twoFingerDragExpectation fulfill]; + }); + [self waitForExpectationsWithTimeout:10 handler:nil]; + + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); + + twoFingerDrag.state = UIGestureRecognizerStateEnded; + [self.mapView handleTwoFingerDragGesture:twoFingerDrag]; + cameraPadding = self.mapView.mbglMap.getCameraOptions().padding; + XCTAssertEqual(padding, cameraPadding, @"When a gesture recognizer is performed contentInsets and camera padding should match."); +} + +@end diff --git a/platform/ios/test/MGLMapViewPitchTests.m b/platform/ios/test/MGLMapViewPitchTests.m index 3e9311dbd4..fa657eb994 100644 --- a/platform/ios/test/MGLMapViewPitchTests.m +++ b/platform/ios/test/MGLMapViewPitchTests.m @@ -2,6 +2,7 @@ #import @interface MockUIPanGestureRecognizer : UIPanGestureRecognizer +@property(nonatomic, readwrite) UIGestureRecognizerState state; @property NSUInteger mbx_numberOfFingersForGesture; @property CGPoint mbx_middlePoint; @property CGPoint mbx_westPoint; @@ -9,6 +10,9 @@ @end @implementation MockUIPanGestureRecognizer + +@synthesize state; + - (instancetype)initWithTarget:(id)target action:(SEL)action { if (self = [super initWithTarget:target action:action]) { self.mbx_numberOfFingersForGesture = 2; diff --git a/platform/ios/test/MGLMockGestureRecognizers.h b/platform/ios/test/MGLMockGestureRecognizers.h index aa5fbec494..29889e39f4 100644 --- a/platform/ios/test/MGLMockGestureRecognizers.h +++ b/platform/ios/test/MGLMockGestureRecognizers.h @@ -4,7 +4,26 @@ @interface UIPinchGestureRecognizerMock : UIPinchGestureRecognizer @property (nonatomic, readwrite) CGFloat velocity; @property (nonatomic) CGPoint locationInViewOverride; +@property(nonatomic, readwrite) UIGestureRecognizerState state; @end @interface UIRotationGestureRecognizerMock : UIRotationGestureRecognizer +@property(nonatomic, readwrite) UIGestureRecognizerState state; +@end + +@interface UITapGestureRecognizerMock : UITapGestureRecognizer +@property (strong, nonatomic) UIView *mockTappedView; +@property (assign) CGPoint mockTappedPoint; +@end + +@interface UILongPressGestureRecognizerMock : UILongPressGestureRecognizer +@property(nonatomic, readwrite) UIGestureRecognizerState state; +@property (assign) CGPoint mockTappedPoint; +@end + +@interface UIPanGestureRecognizerMock : UIPanGestureRecognizer +@property(nonatomic, readwrite) UIGestureRecognizerState state; +@property (assign) CGPoint firstFingerPoint; +@property (assign) CGPoint secondFingerPoint; +@property(nonatomic, readwrite) NSUInteger numberOfTouches; @end diff --git a/platform/ios/test/MGLMockGestureRecognizers.m b/platform/ios/test/MGLMockGestureRecognizers.m index 89df6750a9..c818805174 100644 --- a/platform/ios/test/MGLMockGestureRecognizers.m +++ b/platform/ios/test/MGLMockGestureRecognizers.m @@ -1,11 +1,55 @@ #import "MGLMockGestureRecognizers.h" +#import "objc/runtime.h" @implementation UIPinchGestureRecognizerMock @synthesize velocity; +@synthesize state; - (CGPoint)locationInView:(nullable UIView *)view { return self.locationInViewOverride; } @end @implementation UIRotationGestureRecognizerMock - (CGPoint)locationInView:(nullable UIView*)view { return view.center; } +@synthesize state; +@end + +@implementation UITapGestureRecognizerMock + ++ (void)load { + method_exchangeImplementations(class_getInstanceMethod(self, @selector(state)), + class_getInstanceMethod(self, @selector(mockState))); +} + +- (UIGestureRecognizerState)mockState { + return UIGestureRecognizerStateRecognized; +} + +- (UIView *)view { + return self.mockTappedView; +} + +- (CGPoint)locationInView:(UIView *)view { + return self.mockTappedPoint; +} + +@end + +@implementation UILongPressGestureRecognizerMock +@synthesize state; + +- (CGPoint)locationInView:(UIView *)view { + return self.mockTappedPoint; +} +@end + +@implementation UIPanGestureRecognizerMock +@synthesize state; +@synthesize numberOfTouches; + +- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView *)view { + if (touchIndex) { + return self.secondFingerPoint; + } + return self.firstFingerPoint; +} @end -- cgit v1.2.1 From a90e5f6e97232e9e42ee86df9b07365223528b91 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Sat, 5 Oct 2019 13:06:28 -0400 Subject: [ios, macos] Changed exception to assert and nil return, since attribution methods can be called via user interaction (without a mechanism to try/catch) (#15764) --- platform/darwin/src/MGLImageSource.mm | 7 ++++++- platform/darwin/src/MGLRasterTileSource.mm | 7 ++++++- platform/darwin/src/MGLVectorTileSource.mm | 7 ++++++- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/platform/darwin/src/MGLImageSource.mm b/platform/darwin/src/MGLImageSource.mm index 421cc7a155..2d2f090079 100644 --- a/platform/darwin/src/MGLImageSource.mm +++ b/platform/darwin/src/MGLImageSource.mm @@ -1,6 +1,7 @@ #import "MGLImageSource.h" #import "MGLGeometry_Private.h" +#import "MGLLoggingConfiguration_Private.h" #import "MGLSource_Private.h" #import "MGLTileSource_Private.h" #import "NSURL+MGLAdditions.h" @@ -99,7 +100,11 @@ } - (NSString *)attributionHTMLString { - MGLAssertStyleSourceIsValid(); + if (!self.rawSource) { + MGLAssert(0, @"Source with identifier `%@` was invalidated after a style change", self.identifier); + return nil; + } + auto attribution = self.rawSource->getAttribution(); return attribution ? @(attribution->c_str()) : nil; } diff --git a/platform/darwin/src/MGLRasterTileSource.mm b/platform/darwin/src/MGLRasterTileSource.mm index b31cee296f..80b21cc7dd 100644 --- a/platform/darwin/src/MGLRasterTileSource.mm +++ b/platform/darwin/src/MGLRasterTileSource.mm @@ -1,5 +1,6 @@ #import "MGLRasterTileSource_Private.h" +#import "MGLLoggingConfiguration_Private.h" #import "MGLMapView_Private.h" #import "MGLSource_Private.h" #import "MGLTileSource_Private.h" @@ -72,7 +73,11 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512; } - (NSString *)attributionHTMLString { - MGLAssertStyleSourceIsValid(); + if (!self.rawSource) { + MGLAssert(0, @"Source with identifier `%@` was invalidated after a style change", self.identifier); + return nil; + } + auto attribution = self.rawSource->getAttribution(); return attribution ? @(attribution->c_str()) : nil; } diff --git a/platform/darwin/src/MGLVectorTileSource.mm b/platform/darwin/src/MGLVectorTileSource.mm index 85270c4a49..9ab11e2e56 100644 --- a/platform/darwin/src/MGLVectorTileSource.mm +++ b/platform/darwin/src/MGLVectorTileSource.mm @@ -1,6 +1,7 @@ #import "MGLVectorTileSource_Private.h" #import "MGLFeature_Private.h" +#import "MGLLoggingConfiguration_Private.h" #import "MGLSource_Private.h" #import "MGLTileSource_Private.h" #import "MGLStyle_Private.h" @@ -44,7 +45,11 @@ } - (NSString *)attributionHTMLString { - MGLAssertStyleSourceIsValid(); + if (!self.rawSource) { + MGLAssert(0, @"Source with identifier `%@` was invalidated after a style change", self.identifier); + return nil; + } + auto attribution = self.rawSource->getAttribution(); return attribution ? @(attribution->c_str()) : nil; } -- cgit v1.2.1 From f58a25932a1f0e6e2b4e58129f83bdb641048986 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Wed, 2 Oct 2019 11:11:18 +0300 Subject: [render-test] Add support for setPitch operation --- render-test/runner.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 5c8f53759f..26419e3eae 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -186,6 +186,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { static const std::string setCenterOp("setCenter"); static const std::string setZoomOp("setZoom"); static const std::string setBearingOp("setBearing"); + static const std::string setPitchOp("setPitch"); static const std::string setFilterOp("setFilter"); static const std::string setLayerZoomRangeOp("setLayerZoomRange"); static const std::string setLightOp("setLight"); @@ -307,6 +308,12 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(operationArray[1].IsNumber()); map.jumpTo(mbgl::CameraOptions().withBearing(operationArray[1].GetDouble())); + // setPitch + } else if (operationArray[0].GetString() == setPitchOp) { + assert(operationArray.Size() >= 2u); + assert(operationArray[1].IsNumber()); + map.jumpTo(mbgl::CameraOptions().withPitch(operationArray[1].GetDouble())); + // setFilter } else if (operationArray[0].GetString() == setFilterOp) { assert(operationArray.Size() >= 3u); -- cgit v1.2.1 From 18a426d74808605d7bb333a56de0cb5493094f20 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Wed, 2 Oct 2019 11:13:36 +0300 Subject: [render-test] Support feature-state tests where featureID is a number --- render-test/runner.cpp | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 26419e3eae..fa7a86e948 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -490,7 +490,11 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { sourceLayer = {featureOptions["sourceLayer"].GetString()}; } if (featureOptions.HasMember("id")) { - featureID = featureOptions["id"].GetString(); + if (featureOptions["id"].IsString()) { + featureID = featureOptions["id"].GetString(); + } else if (featureOptions["id"].IsNumber()) { + featureID = mbgl::util::toString(featureOptions["id"].GetUint64()); + } } const JSValue* state = &operationArray[2]; @@ -514,7 +518,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { result[k] = std::move(array); stateValue = std::move(result); valueParsed = true; - return {}; + return nullopt; } else if (isObject(v)) { eachMember(v, convertFn); @@ -555,7 +559,11 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { sourceLayer = {featureOptions["sourceLayer"].GetString()}; } if (featureOptions.HasMember("id")) { - featureID = featureOptions["id"].GetString(); + if (featureOptions["id"].IsString()) { + featureID = featureOptions["id"].GetString(); + } else if (featureOptions["id"].IsNumber()) { + featureID = mbgl::util::toString(featureOptions["id"].GetUint64()); + } } try { @@ -584,7 +592,11 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { sourceLayer = {featureOptions["sourceLayer"].GetString()}; } if (featureOptions.HasMember("id")) { - featureID = featureOptions["id"].GetString(); + if (featureOptions["id"].IsString()) { + featureID = featureOptions["id"].GetString(); + } else if (featureOptions["id"].IsNumber()) { + featureID = mbgl::util::toString(featureOptions["id"].GetUint64()); + } } if (operationArray.Size() >= 3u) { -- cgit v1.2.1 From 13801f1b80e21e128b851caa58a9f4bbd2421844 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Wed, 2 Oct 2019 13:26:39 +0300 Subject: [render-test] Add support for query tests --- .../debug/collision-lines-overscaled/expected.png | Bin 7774 -> 0 bytes .../debug/collision-lines-pitched/expected.png | Bin 165500 -> 0 bytes .../expected/debug/collision-lines/expected.png | Bin 196454 -> 0 bytes .../debug/collision-pitched-wrapped/expected.png | Bin 69725 -> 0 bytes .../debug/collision-lines-overscaled/expected.png | Bin 0 -> 7774 bytes .../debug/collision-lines-pitched/expected.png | Bin 0 -> 165500 bytes .../debug/collision-lines/expected.png | Bin 0 -> 196454 bytes .../debug/collision-pitched-wrapped/expected.png | Bin 0 -> 69725 bytes .../symbol-visibility/visible/expected.png | Bin 0 -> 14729 bytes .../auto-text-rotation-alignment-map/expected.png | Bin 0 -> 26157 bytes .../map-text-rotation-alignment-map/expected.png | Bin 0 -> 26157 bytes .../expected.png | Bin 0 -> 26866 bytes .../pitched-rotated-debug/expected.png | Bin 0 -> 43135 bytes .../rotated-offset/expected.png | Bin 0 -> 35553 bytes .../symbol-visibility/visible/expected.png | Bin 14729 -> 0 bytes .../auto-text-rotation-alignment-map/expected.png | Bin 26157 -> 0 bytes .../map-text-rotation-alignment-map/expected.png | Bin 26157 -> 0 bytes .../expected.png | Bin 26866 -> 0 bytes .../pitched-rotated-debug/expected.png | Bin 43135 -> 0 bytes .../rotated-offset/expected.png | Bin 35553 -> 0 bytes render-test/main.cpp | 2 +- render-test/metadata.hpp | 7 + render-test/parser.cpp | 134 ++++++++++- render-test/parser.hpp | 3 + render-test/runner.cpp | 254 ++++++++++++++++++++- render-test/runner.hpp | 5 +- 26 files changed, 387 insertions(+), 18 deletions(-) delete mode 100644 render-test/expected/debug/collision-lines-overscaled/expected.png delete mode 100644 render-test/expected/debug/collision-lines-pitched/expected.png delete mode 100644 render-test/expected/debug/collision-lines/expected.png delete mode 100644 render-test/expected/debug/collision-pitched-wrapped/expected.png create mode 100644 render-test/expected/render-tests/debug/collision-lines-overscaled/expected.png create mode 100644 render-test/expected/render-tests/debug/collision-lines-pitched/expected.png create mode 100644 render-test/expected/render-tests/debug/collision-lines/expected.png create mode 100644 render-test/expected/render-tests/debug/collision-pitched-wrapped/expected.png create mode 100644 render-test/expected/render-tests/symbol-visibility/visible/expected.png create mode 100644 render-test/expected/render-tests/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png create mode 100644 render-test/expected/render-tests/text-pitch-alignment/map-text-rotation-alignment-map/expected.png create mode 100644 render-test/expected/render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png create mode 100644 render-test/expected/render-tests/text-variable-anchor/pitched-rotated-debug/expected.png create mode 100644 render-test/expected/render-tests/text-variable-anchor/rotated-offset/expected.png delete mode 100644 render-test/expected/symbol-visibility/visible/expected.png delete mode 100644 render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png delete mode 100644 render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png delete mode 100644 render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png delete mode 100644 render-test/expected/text-variable-anchor/pitched-rotated-debug/expected.png delete mode 100644 render-test/expected/text-variable-anchor/rotated-offset/expected.png diff --git a/render-test/expected/debug/collision-lines-overscaled/expected.png b/render-test/expected/debug/collision-lines-overscaled/expected.png deleted file mode 100644 index 38eb0d2da6..0000000000 Binary files a/render-test/expected/debug/collision-lines-overscaled/expected.png and /dev/null differ diff --git a/render-test/expected/debug/collision-lines-pitched/expected.png b/render-test/expected/debug/collision-lines-pitched/expected.png deleted file mode 100644 index 416d7d5715..0000000000 Binary files a/render-test/expected/debug/collision-lines-pitched/expected.png and /dev/null differ diff --git a/render-test/expected/debug/collision-lines/expected.png b/render-test/expected/debug/collision-lines/expected.png deleted file mode 100644 index 3f4790a585..0000000000 Binary files a/render-test/expected/debug/collision-lines/expected.png and /dev/null differ diff --git a/render-test/expected/debug/collision-pitched-wrapped/expected.png b/render-test/expected/debug/collision-pitched-wrapped/expected.png deleted file mode 100644 index 9b718c09c0..0000000000 Binary files a/render-test/expected/debug/collision-pitched-wrapped/expected.png and /dev/null differ diff --git a/render-test/expected/render-tests/debug/collision-lines-overscaled/expected.png b/render-test/expected/render-tests/debug/collision-lines-overscaled/expected.png new file mode 100644 index 0000000000..38eb0d2da6 Binary files /dev/null and b/render-test/expected/render-tests/debug/collision-lines-overscaled/expected.png differ diff --git a/render-test/expected/render-tests/debug/collision-lines-pitched/expected.png b/render-test/expected/render-tests/debug/collision-lines-pitched/expected.png new file mode 100644 index 0000000000..416d7d5715 Binary files /dev/null and b/render-test/expected/render-tests/debug/collision-lines-pitched/expected.png differ diff --git a/render-test/expected/render-tests/debug/collision-lines/expected.png b/render-test/expected/render-tests/debug/collision-lines/expected.png new file mode 100644 index 0000000000..3f4790a585 Binary files /dev/null and b/render-test/expected/render-tests/debug/collision-lines/expected.png differ diff --git a/render-test/expected/render-tests/debug/collision-pitched-wrapped/expected.png b/render-test/expected/render-tests/debug/collision-pitched-wrapped/expected.png new file mode 100644 index 0000000000..9b718c09c0 Binary files /dev/null and b/render-test/expected/render-tests/debug/collision-pitched-wrapped/expected.png differ diff --git a/render-test/expected/render-tests/symbol-visibility/visible/expected.png b/render-test/expected/render-tests/symbol-visibility/visible/expected.png new file mode 100644 index 0000000000..8da157772a Binary files /dev/null and b/render-test/expected/render-tests/symbol-visibility/visible/expected.png differ diff --git a/render-test/expected/render-tests/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png b/render-test/expected/render-tests/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png new file mode 100644 index 0000000000..cd690ca152 Binary files /dev/null and b/render-test/expected/render-tests/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png differ diff --git a/render-test/expected/render-tests/text-pitch-alignment/map-text-rotation-alignment-map/expected.png b/render-test/expected/render-tests/text-pitch-alignment/map-text-rotation-alignment-map/expected.png new file mode 100644 index 0000000000..cd690ca152 Binary files /dev/null and b/render-test/expected/render-tests/text-pitch-alignment/map-text-rotation-alignment-map/expected.png differ diff --git a/render-test/expected/render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png b/render-test/expected/render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png new file mode 100644 index 0000000000..764d4a0b24 Binary files /dev/null and b/render-test/expected/render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png differ diff --git a/render-test/expected/render-tests/text-variable-anchor/pitched-rotated-debug/expected.png b/render-test/expected/render-tests/text-variable-anchor/pitched-rotated-debug/expected.png new file mode 100644 index 0000000000..4e3d012844 Binary files /dev/null and b/render-test/expected/render-tests/text-variable-anchor/pitched-rotated-debug/expected.png differ diff --git a/render-test/expected/render-tests/text-variable-anchor/rotated-offset/expected.png b/render-test/expected/render-tests/text-variable-anchor/rotated-offset/expected.png new file mode 100644 index 0000000000..13690d147c Binary files /dev/null and b/render-test/expected/render-tests/text-variable-anchor/rotated-offset/expected.png differ diff --git a/render-test/expected/symbol-visibility/visible/expected.png b/render-test/expected/symbol-visibility/visible/expected.png deleted file mode 100644 index 8da157772a..0000000000 Binary files a/render-test/expected/symbol-visibility/visible/expected.png and /dev/null differ diff --git a/render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png b/render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png deleted file mode 100644 index cd690ca152..0000000000 Binary files a/render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png and /dev/null differ diff --git a/render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png b/render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png deleted file mode 100644 index cd690ca152..0000000000 Binary files a/render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png and /dev/null differ diff --git a/render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png b/render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png deleted file mode 100644 index 764d4a0b24..0000000000 Binary files a/render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png and /dev/null differ diff --git a/render-test/expected/text-variable-anchor/pitched-rotated-debug/expected.png b/render-test/expected/text-variable-anchor/pitched-rotated-debug/expected.png deleted file mode 100644 index 4e3d012844..0000000000 Binary files a/render-test/expected/text-variable-anchor/pitched-rotated-debug/expected.png and /dev/null differ diff --git a/render-test/expected/text-variable-anchor/rotated-offset/expected.png b/render-test/expected/text-variable-anchor/rotated-offset/expected.png deleted file mode 100644 index 13690d147c..0000000000 Binary files a/render-test/expected/text-variable-anchor/rotated-offset/expected.png and /dev/null differ diff --git a/render-test/main.cpp b/render-test/main.cpp index fcdbe3ab55..6f5e2449a9 100644 --- a/render-test/main.cpp +++ b/render-test/main.cpp @@ -81,7 +81,7 @@ int main(int argc, char** argv) { bool shouldIgnore = false; std::string ignoreReason; - const std::string ignoreName = "render-tests/" + id; + const std::string ignoreName = id; const auto it = std::find_if(ignores.cbegin(), ignores.cend(), [&ignoreName](auto pair) { return pair.first == ignoreName; }); if (it != ignores.end()) { shouldIgnore = true; diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index d23a0fb296..d25b81c7ab 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -1,9 +1,11 @@ #pragma once +#include #include #include #include +#include #include "filesystem.hpp" @@ -50,6 +52,7 @@ struct TestMetadata { TestPaths paths; mbgl::JSDocument document; + bool renderTest = true; mbgl::Size size{ 512u, 512u }; float pixelRatio = 1.0f; @@ -61,6 +64,9 @@ struct TestMetadata { bool axonometric = false; double xSkew = 0.0; double ySkew = 1.0; + mbgl::ScreenCoordinate queryGeometry{0u, 0u}; + mbgl::ScreenBox queryGeometryBox{{0u, 0u}, {0u, 0u}}; + mbgl::RenderedQueryOptions queryOptions; // TODO uint32_t fadeDuration = 0; @@ -72,6 +78,7 @@ struct TestMetadata { std::string color; std::string actual; + std::string actualJson; std::string expected; std::string diff; diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 9b462dee72..802c3c7f55 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -5,9 +5,14 @@ #include +#include #include #include +#include +#include +#include + #include #include #include @@ -179,8 +184,67 @@ TestPaths makeTestPaths(mbgl::filesystem::path stylePath) { }; } +void writeJSON(rapidjson::PrettyWriter& writer, const mbgl::Value& value) { + value.match([&writer](const mbgl::NullValue&) { writer.Null(); }, + [&writer](bool b) { writer.Bool(b); }, + [&writer](uint64_t u) { writer.Uint64(u); }, + [&writer](int64_t i) { writer.Int64(i); }, + [&writer](double d) { d == std::floor(d) ? writer.Int64(d) : writer.Double(d); }, + [&writer](const std::string& s) { writer.String(s); }, + [&writer](const std::vector& arr) { + writer.StartArray(); + for (const auto& item : arr) { + writeJSON(writer, item); + } + writer.EndArray(); + }, + [&writer](const std::unordered_map& obj) { + writer.StartObject(); + std::map sorted(obj.begin(), obj.end()); + for (const auto& entry : sorted) { + writer.Key(entry.first.c_str()); + writeJSON(writer, entry.second); + } + writer.EndObject(); + }); +} + } // namespace +std::string toJSON(const mbgl::Value& value, unsigned indent, bool singleLine) { + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + if (singleLine) { + writer.SetFormatOptions(rapidjson::kFormatSingleLineArray); + } + writer.SetIndent(' ', indent); + writeJSON(writer, value); + return buffer.GetString(); +} + +std::string toJSON(const std::vector& features, unsigned indent, bool singleLine) { + rapidjson::CrtAllocator allocator; + rapidjson::StringBuffer buffer; + rapidjson::PrettyWriter writer(buffer); + if (singleLine) { + writer.SetFormatOptions(rapidjson::kFormatSingleLineArray); + } + writer.SetIndent(' ', indent); + writer.StartArray(); + for (size_t i = 0; i < features.size(); ++i) { + auto result = mapbox::geojson::convert(features[i], allocator); + + result.AddMember("source", features[i].source, allocator); + if (!features[i].sourceLayer.empty()) { + result.AddMember("sourceLayer", features[i].sourceLayer, allocator); + } + result.AddMember("state", mapbox::geojson::to_value{allocator}(features[i].state), allocator); + result.Accept(writer); + } + writer.EndArray(); + return buffer.GetString(); +} + JSONReply readJson(const mbgl::filesystem::path& jsonPath) { auto maybeJSON = mbgl::util::readFile(jsonPath); if (!maybeJSON) { @@ -228,7 +292,7 @@ std::string serializeMetrics(const TestMetrics& metrics) { } std::vector readExpectedEntries(const mbgl::filesystem::path& base) { - static const std::regex regex(".*expected.*.png"); + static const std::regex regex(".*expected.*.png|.*expected.*.json"); std::vector expectedImages; for (const auto& entry : mbgl::filesystem::directory_iterator(base)) { @@ -476,6 +540,45 @@ TestMetadata parseTestMetadata(const TestPaths& paths) { metadata.ySkew = testValue["skew"][1].GetDouble(); } + if (testValue.HasMember("queryGeometry")) { + assert(testValue["queryGeometry"].IsArray()); + if (testValue["queryGeometry"][0].IsNumber() && testValue["queryGeometry"][1].IsNumber()) { + metadata.queryGeometry.x = testValue["queryGeometry"][0].GetDouble(); + metadata.queryGeometry.y = testValue["queryGeometry"][1].GetDouble(); + } else if (testValue["queryGeometry"][0].IsArray() && testValue["queryGeometry"][1].IsArray()) { + metadata.queryGeometryBox.min.x = testValue["queryGeometry"][0][0].GetDouble(); + metadata.queryGeometryBox.min.y = testValue["queryGeometry"][0][1].GetDouble(); + metadata.queryGeometryBox.max.x = testValue["queryGeometry"][1][0].GetDouble(); + metadata.queryGeometryBox.max.y = testValue["queryGeometry"][1][1].GetDouble(); + } + metadata.renderTest = false; + } + + if (testValue.HasMember("queryOptions")) { + assert(testValue["queryOptions"].IsObject()); + + if (testValue["queryOptions"].HasMember("layers")) { + assert(testValue["queryOptions"]["layers"].IsArray()); + auto layersArray = testValue["queryOptions"]["layers"].GetArray(); + std::vector layersVec; + for (uint32_t i = 0; i < layersArray.Size(); i++) { + layersVec.emplace_back(testValue["queryOptions"]["layers"][i].GetString()); + } + metadata.queryOptions.layerIDs = layersVec; + } + + using namespace mbgl::style; + using namespace mbgl::style::conversion; + if (testValue["queryOptions"].HasMember("filter")) { + assert(testValue["queryOptions"]["filter"].IsArray()); + auto& filterVal = testValue["queryOptions"]["filter"]; + Error error; + mbgl::optional converted = convert(filterVal, error); + assert(converted); + metadata.queryOptions.filter = std::move(*converted); + } + } + // TODO: fadeDuration // TODO: addFakeCanvas @@ -499,20 +602,31 @@ std::string createResultItem(const TestMetadata& metadata, bool hasFailedTests) html.append("
\n"); html.append(R"(

" + metadata.status + " " + metadata.id + "

\n"); if (metadata.status != "errored") { - html.append("\n"); - - html.append("\n"); + if (metadata.renderTest) { + html.append("\n"); + + html.append("\n"); + } else { + html.append("\n"); + } } else { assert(!metadata.errorMessage.empty()); html.append("

Error: " + metadata.errorMessage + "

\n"); } if (metadata.difference != 0.0) { - html.append("

Diff: " + mbgl::util::toString(metadata.difference) + "

\n"); + if (metadata.renderTest) { + html.append("

Diff: " + mbgl::util::toString(metadata.difference) + + "

\n"); + } else { + html.append("

Diff: " + metadata.diff + "

\n"); + } } html.append("
\n"); diff --git a/render-test/parser.hpp b/render-test/parser.hpp index 94fb212944..afa281ad30 100644 --- a/render-test/parser.hpp +++ b/render-test/parser.hpp @@ -31,5 +31,8 @@ std::string createResultPage(const TestStatistics&, const std::vector& features, unsigned indent, bool singleLine); + void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document); void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document); \ No newline at end of file diff --git a/render-test/runner.cpp b/render-test/runner.cpp index fa7a86e948..868e1a9a32 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -30,10 +30,11 @@ #include #include +using namespace mbgl; + // static const std::string& TestRunner::getBasePath() { - const static std::string result = - std::string(TEST_RUNNER_ROOT_PATH).append("/mapbox-gl-js/test/integration/render-tests"); + const static std::string result = std::string(TEST_RUNNER_ROOT_PATH).append("/mapbox-gl-js/test/integration"); return result; } @@ -46,7 +47,236 @@ const std::vector& TestRunner::getPlatformExpectationsPaths() { return result; } -bool TestRunner::checkResults(mbgl::PremultipliedImage&& actualImage, TestMetadata& metadata) { +// Strip precision for numbers, so that we can compare evaluated results with fixtures. +// Copied from JS expression harness. +Value stripPrecision(const Value& value) { + const double decimalSigFigs = 6; + if (auto num = numericValue(value)) { + if (*num == 0) { + return *num; + } + + const double multiplier = std::pow(10, std::max(0.0, decimalSigFigs - std::ceil(std::log10(std::fabs(*num))))); + + // We strip precision twice in a row here to avoid cases where + // stripping an already stripped number will modify its value + // due to bad floating point precision luck + // eg `Math.floor(8.16598 * 100000) / 100000` -> 8.16597 + const double firstStrip = std::floor(*num * multiplier) / multiplier; + return std::floor(firstStrip * multiplier) / multiplier; + } + + if (value.getArray()) { + std::vector stripped; + const auto& vec = *value.getArray(); + stripped.reserve(vec.size()); + for (const auto& val : vec) { + stripped.emplace_back(stripPrecision(val)); + } + return stripped; + } else if (value.getObject()) { + std::unordered_map stripped; + const auto& map = *value.getObject(); + for (const auto& pair : map) { + stripped.emplace(pair.first, stripPrecision(pair.second)); + } + return stripped; + } + + return value; +} + +bool deepEqual(const Value& a, const Value& b) { + const auto& anum = numericValue(a); + const auto& bnum = numericValue(b); + if (anum && bnum) { + return stripPrecision(*anum) == stripPrecision(*bnum); + } + + if (a.which() != b.which()) { + return false; + } + + if (a.getArray() && b.getArray()) { + const auto& avec = *a.getArray(); + const auto& bvec = *b.getArray(); + if (avec.size() != bvec.size()) { + return false; + } + for (std::size_t i = 0; i < avec.size(); ++i) { + if (!deepEqual(avec[i], bvec[i])) { + return false; + } + } + return true; + } + + if (a.getObject() && b.getObject()) { + const auto& amap = *a.getObject(); + const auto& bmap = *b.getObject(); + if (amap.size() != bmap.size()) { + return false; + } + for (const auto& pair : amap) { + auto it = bmap.find(pair.first); + if (it == bmap.end()) { + return false; + } + if (!deepEqual(pair.second, it->second)) { + return false; + } + } + return true; + } + + if (a == b) { + return true; + } + + if (a.getString() && b.getString()) { + const auto& strA = *a.getString(); + const auto& strB = *b.getString(); + if (strA == strB) { + return true; + } + + try { + double numA = std::stod(strA); + double numB = std::stod(strB); + return stripPrecision(numA) == stripPrecision(numB); + } catch (...) { + } + } + + return false; +} + +std::vector tokenize(std::string str) { + std::vector tokens; + std::regex re("\n"); + std::copy(std::regex_token_iterator(str.begin(), str.end(), re, -1), + std::regex_token_iterator(), + std::back_inserter(tokens)); + return tokens; +} + +std::string simpleDiff(const Value& result, const Value& expected) { + std::vector resultTokens{tokenize(toJSON(result, 2, false))}; + std::vector expectedTokens{tokenize(toJSON(expected, 2, false))}; + std::size_t maxLength = std::max(resultTokens.size(), expectedTokens.size()); + std::ostringstream diff; + + diff << "
" << std::endl;
+    const auto flush =
+        [](const std::vector& vec, std::size_t pos, std::ostringstream& out, std::string separator) {
+            for (std::size_t j = pos; j < vec.size(); ++j) {
+                out << separator << vec[j] << std::endl;
+            }
+        };
+
+    for (std::size_t i = 0; i < maxLength; ++i) {
+        if (resultTokens.size() <= i) {
+            flush(expectedTokens, i, diff, "-");
+            break;
+        }
+
+        if (expectedTokens.size() <= i) {
+            flush(resultTokens, i, diff, "+");
+            break;
+        }
+
+        if (!deepEqual(resultTokens[i], expectedTokens[i])) {
+            diff << ""
+                 << "-" << expectedTokens[i] << "" << std::endl;
+            diff << ""
+                 << "+" << resultTokens[i] << "" << std::endl;
+        } else {
+            diff << resultTokens[i] << std::endl;
+        }
+    }
+    diff << "
" << std::endl; + return diff.str(); +} + +bool TestRunner::checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, + std::vector&& features, + TestMetadata& metadata) { + const std::string& base = metadata.paths.defaultExpectations(); + const std::vector& expectations = metadata.paths.expectations; + + metadata.actual = mbgl::encodePNG(actualImage); + + if (actualImage.size.isEmpty()) { + metadata.errorMessage = "Invalid size for actual image"; + return false; + } + + metadata.actualJson = toJSON(features, 2, false); + + if (metadata.actualJson.empty()) { + metadata.errorMessage = "Invalid size for actual JSON"; + return false; + } + +#if !TEST_READ_ONLY + if (getenv("UPDATE_PLATFORM")) { + mbgl::filesystem::create_directories(expectations.back()); + mbgl::util::write_file(expectations.back().string() + "/expected.json", metadata.actualJson); + return true; + } else if (getenv("UPDATE_DEFAULT")) { + mbgl::util::write_file(base + "/expected.json", metadata.actualJson); + return true; + } + + mbgl::util::write_file(base + "/actual.json", metadata.actualJson); +#endif + + std::vector expectedJsonPaths; + mbgl::filesystem::path expectedMetricsPath; + for (auto rit = expectations.rbegin(); rit != expectations.rend(); ++rit) { + if (mbgl::filesystem::exists(*rit)) { + expectedJsonPaths = readExpectedEntries(*rit); + if (!expectedJsonPaths.empty()) break; + } + } + + if (expectedJsonPaths.empty()) { + metadata.errorMessage = "Failed to find expectations for: " + metadata.paths.stylePath.string(); + return false; + } + + for (const auto& entry : expectedJsonPaths) { + auto maybeExpectedJson = readJson(entry); + if (maybeExpectedJson.is()) { + auto& expected = maybeExpectedJson.get(); + + mbgl::JSDocument actual; + actual.Parse<0>(metadata.actualJson); + if (actual.HasParseError()) { + metadata.errorMessage = "Error parsing actual JSON for: " + metadata.paths.stylePath.string(); + return false; + } + + auto actualVal = mapbox::geojson::convert(actual); + auto expectedVal = mapbox::geojson::convert(expected); + bool equal = deepEqual(actualVal, expectedVal); + + metadata.difference = !equal; + if (equal) { + metadata.diff = "Match"; + } else { + metadata.diff = simpleDiff(actualVal, expectedVal); + } + } else { + metadata.errorMessage = "Failed to load expected JSON " + entry; + return false; + } + } + + return true; +} + +bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, TestMetadata& metadata) { const std::string& base = metadata.paths.defaultExpectations(); const std::vector& expectations = metadata.paths.expectations; @@ -308,13 +538,13 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(operationArray[1].IsNumber()); map.jumpTo(mbgl::CameraOptions().withBearing(operationArray[1].GetDouble())); - // setPitch + // setPitch } else if (operationArray[0].GetString() == setPitchOp) { assert(operationArray.Size() >= 2u); assert(operationArray[1].IsNumber()); map.jumpTo(mbgl::CameraOptions().withPitch(operationArray[1].GetDouble())); - // setFilter + // setFilter } else if (operationArray[0].GetString() == setFilterOp) { assert(operationArray.Size() >= 3u); assert(operationArray[1].IsString()); @@ -665,7 +895,19 @@ bool TestRunner::run(TestMetadata& metadata) { return false; } - return checkResults(std::move(image), metadata); + if (metadata.renderTest) { + return checkRenderTestResults(std::move(image), metadata); + } else { + std::vector features; + assert(metadata.document["metadata"]["test"]["queryGeometry"].IsArray()); + if (metadata.document["metadata"]["test"]["queryGeometry"][0].IsNumber() && + metadata.document["metadata"]["test"]["queryGeometry"][1].IsNumber()) { + features = frontend.getRenderer()->queryRenderedFeatures(metadata.queryGeometry, metadata.queryOptions); + } else { + features = frontend.getRenderer()->queryRenderedFeatures(metadata.queryGeometryBox, metadata.queryOptions); + } + return checkQueryTestResults(std::move(image), std::move(features), metadata); + } } void TestRunner::reset() { diff --git a/render-test/runner.hpp b/render-test/runner.hpp index fdea65e104..d8e5275f61 100644 --- a/render-test/runner.hpp +++ b/render-test/runner.hpp @@ -21,7 +21,10 @@ public: private: bool runOperations(const std::string& key, TestMetadata&); - bool checkResults(mbgl::PremultipliedImage&& image, TestMetadata&); + bool checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, + std::vector&& features, + TestMetadata&); + bool checkRenderTestResults(mbgl::PremultipliedImage&& image, TestMetadata&); struct Impl { Impl(const TestMetadata&); -- cgit v1.2.1 From e96c659906b0e992f50c54fc2b789c38aa18875d Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Wed, 2 Oct 2019 15:49:31 +0300 Subject: [expression-test] fix result diffing --- expression-test/expression_test_runner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/expression-test/expression_test_runner.cpp b/expression-test/expression_test_runner.cpp index 695d129049..e52c9b1186 100644 --- a/expression-test/expression_test_runner.cpp +++ b/expression-test/expression_test_runner.cpp @@ -136,12 +136,12 @@ std::string simpleDiff(const Value& result, const Value& expected) { for (std::size_t i = 0; i < maxLength; ++i) { if (resultTokens.size() <= i) { - flush(expectedTokens, i, diff, "+"s); + flush(expectedTokens, i, diff, "-"s); break; } if (expectedTokens.size() <= i) { - flush(expectedTokens, i, diff, "-"s); + flush(resultTokens, i, diff, "+"s); break; } -- cgit v1.2.1 From bd283fc1be2f90ce02b37617411a0ce4246d898e Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Wed, 2 Oct 2019 13:49:11 +0300 Subject: [build] enable query tests on native test runner --- circle.yml | 42 +++++++++++++++++++++++++++++++++++------ next/render-test/CMakeLists.txt | 3 +++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/circle.yml b/circle.yml index 4210620935..6813aa6c9f 100644 --- a/circle.yml +++ b/circle.yml @@ -591,7 +591,15 @@ commands: - run: name: Run render tests (mbgl-render-test) command: | - build/mbgl-render-test --recycle-map --shuffle + build/mbgl-render-test render-tests render-tests --recycle-map --shuffle + no_output_timeout: 2m + + run-macos-query-tests: + steps: + - run: + name: Run query tests + command: | + build/mbgl-render-test query-tests no_output_timeout: 2m run-linux-render-tests: @@ -604,7 +612,19 @@ commands: name: Run render tests (mbgl-render-test) command: | xvfb-run --server-args="-screen 0 1024x768x24" \ - logbt -- apitrace trace --api=egl -v build/mbgl-render-test --recycle-map --shuffle + logbt -- apitrace trace --api=egl -v build/mbgl-render-test render-tests --recycle-map --shuffle + + run-linux-query-tests: + parameters: + node_version: + type: string + default: v8 + steps: + - run: + name: Run query tests + command: | + xvfb-run --server-args="-screen 0 1024x768x24" \ + logbt -- apitrace trace --api=egl -v build/mbgl-render-test query-tests run-unit-tests: steps: @@ -647,9 +667,15 @@ commands: upload-render-tests: steps: - store_artifacts: - path: mapbox-gl-js/test/integration/render-tests/index.html + path: mapbox-gl-js/test/integration/index.html destination: render-tests + upload-query-tests: + steps: + - store_artifacts: + path: mapbox-gl-js/test/integration/index.html + destination: query-tests + collect-xcode-build-logs: steps: - run: @@ -1240,10 +1266,12 @@ jobs: - build-mbgl-expression-test - build-mbgl-render-test - run-expression-tests - - run-linux-render-tests - - save-dependencies - upload-expression-tests + - run-linux-render-tests - upload-render-tests + - run-linux-query-tests + - upload-query-tests + - save-dependencies # ------------------------------------------------------------------------------ ios-debug: @@ -1534,9 +1562,11 @@ jobs: - build-mbgl-render-test - save-dependencies - run-expression-tests - - run-macos-render-tests - upload-expression-tests + - run-macos-render-tests - upload-render-tests + - run-macos-query-tests + - upload-query-tests # ------------------------------------------------------------------------------ metrics-nightly: diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 6cab3fed52..6edd11ca95 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -42,9 +42,12 @@ add_test( NAME mbgl-render-test COMMAND mbgl-render-test + render-tests --recycle-map --shuffle --seed ${MBGL_RENDER_TEST_SEED} WORKING_DIRECTORY ${MBGL_ROOT} ) + +add_test(NAME mbgl-query-test COMMAND mbgl-render-test query-tests WORKING_DIRECTORY ${MBGL_ROOT}) -- cgit v1.2.1 From 23cebe20fed0e3ebc3328c6345af4e32d86cfcf5 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 7 Oct 2019 15:45:45 +0300 Subject: [core] Introduce SequencedScheduler and ParallelScheduler This commit refactors `utils::ThreadPool` into a template `ThreadedScheduler` class and provides aux type aliases. So that it is possible to obtain a sequenced schedule,where all the scheduled tasks are guarantied to be executed consequently. The sequenced lightweight scheduler is required by both the orchestration thread and the refactored `FileSource` implementation. --- src/mbgl/actor/scheduler.cpp | 2 +- src/mbgl/util/thread_pool.cpp | 62 +++++++++++++++++++------------------------ src/mbgl/util/thread_pool.hpp | 53 +++++++++++++++++++++++++++++++----- 3 files changed, 74 insertions(+), 43 deletions(-) diff --git a/src/mbgl/actor/scheduler.cpp b/src/mbgl/actor/scheduler.cpp index cb0c7728ec..5fd9a133bd 100644 --- a/src/mbgl/actor/scheduler.cpp +++ b/src/mbgl/actor/scheduler.cpp @@ -28,7 +28,7 @@ std::shared_ptr Scheduler::GetBackground() { std::shared_ptr scheduler = weak.lock(); if (!scheduler) { - weak = scheduler = std::make_shared(4); + weak = scheduler = std::make_shared(); } return scheduler; diff --git a/src/mbgl/util/thread_pool.cpp b/src/mbgl/util/thread_pool.cpp index d8df0cd575..040e996dd4 100644 --- a/src/mbgl/util/thread_pool.cpp +++ b/src/mbgl/util/thread_pool.cpp @@ -6,49 +6,41 @@ namespace mbgl { -ThreadPool::ThreadPool(std::size_t count) { - threads.reserve(count); - - for (std::size_t i = 0; i < count; ++i) { - threads.emplace_back([this, i]() { - platform::setCurrentThreadName(std::string{ "Worker " } + util::toString(i + 1)); - platform::attachThread(); - - while (true) { - std::unique_lock lock(mutex); - - cv.wait(lock, [this] { - return !queue.empty() || terminate; - }); - - if (terminate) { - platform::detachThread(); - return; - } - - auto function = std::move(queue.front()); - queue.pop(); - lock.unlock(); - if (function) function(); - } - }); - } -} +ThreadedSchedulerBase::~ThreadedSchedulerBase() = default; -ThreadPool::~ThreadPool() { +void ThreadedSchedulerBase::terminate() { { std::lock_guard lock(mutex); - terminate = true; + terminated = true; } - cv.notify_all(); +} - for (auto& thread : threads) { - thread.join(); - } +std::thread ThreadedSchedulerBase::makeSchedulerThread(size_t index) { + return std::thread([this, index]() { + platform::setCurrentThreadName(std::string{"Worker "} + util::toString(index + 1)); + platform::attachThread(); + + while (true) { + std::unique_lock lock(mutex); + + cv.wait(lock, [this] { return !queue.empty() || terminated; }); + + if (terminated) { + platform::detachThread(); + return; + } + + auto function = std::move(queue.front()); + queue.pop(); + lock.unlock(); + if (function) function(); + } + }); } -void ThreadPool::schedule(std::function fn) { +void ThreadedSchedulerBase::schedule(std::function fn) { + assert(fn); { std::lock_guard lock(mutex); queue.push(std::move(fn)); diff --git a/src/mbgl/util/thread_pool.hpp b/src/mbgl/util/thread_pool.hpp index 96fc13bda5..f302e50914 100644 --- a/src/mbgl/util/thread_pool.hpp +++ b/src/mbgl/util/thread_pool.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -10,19 +11,57 @@ namespace mbgl { -class ThreadPool final : public Scheduler { +class ThreadedSchedulerBase : public Scheduler { public: - explicit ThreadPool(std::size_t count); - ~ThreadPool() override; - void schedule(std::function) override; -private: - std::vector threads; +protected: + ThreadedSchedulerBase() = default; + ~ThreadedSchedulerBase() override; + + void terminate(); + std::thread makeSchedulerThread(size_t index); + std::queue> queue; std::mutex mutex; std::condition_variable cv; - bool terminate{ false }; + bool terminated{false}; }; +/** + * @brief ThreadScheduler implements Scheduler interface using a lightweight event loop + * + * @tparam N number of threads + * + * Note: If N == 1 all scheduled tasks are guaranteed to execute consequently; + * otherwise, some of the scheduled tasks might be executed in parallel. + */ +template +class ThreadedScheduler : public ThreadedSchedulerBase { +public: + ThreadedScheduler() { + for (std::size_t i = 0u; i < N; ++i) { + threads[i] = makeSchedulerThread(i); + } + } + + ~ThreadedScheduler() override { + terminate(); + for (auto& thread : threads) { + thread.join(); + } + } + +private: + std::array threads; + static_assert(N > 0, "Thread count must be more than zero."); +}; + +using SequencedScheduler = ThreadedScheduler<1>; + +template +using ParallelScheduler = ThreadedScheduler<1 + extra>; + +using ThreadPool = ParallelScheduler<3>; + } // namespace mbgl -- cgit v1.2.1 From 9be5ccb2104a7f41dc8b1f7c7d754c6aa5d3fd53 Mon Sep 17 00:00:00 2001 From: Chloe Krawczyk Date: Mon, 7 Oct 2019 22:39:22 -0700 Subject: [docs] add SMCalloutView to LICENSE.md (#15774) --- LICENSE.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index f4abdd104f..b544bf3ad3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -863,4 +863,16 @@ limitations under the License. =========================================================================== -Mapbox GL uses portions of software mentioned in [platform/android/LICENSE.md](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/LICENSE.md). +Mapbox GL uses portions of SMCalloutView. + +Copyright 2016 Nick Farina. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License: +https://github.com/nfarina/calloutview/blob/master/LICENSE + +=========================================================================== + +Mapbox GL uses portions of software listed in [platform/android/LICENSE.md](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/LICENSE.md). + +Mapbox GL uses portions of software listed in [platform/ios/vendor/mapbox-events-ios/LICENSE.md](https://github.com/mapbox/mobile-events-ios/blob/master/LICENSE.md). -- cgit v1.2.1 From 4eaaa9046ed4f2c45a9febdb8f2f15a8f63f73d4 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Mon, 7 Oct 2019 12:44:16 +0300 Subject: [tests] Share common code between test runners --- cmake/expression-test.cmake | 2 + cmake/render-test.cmake | 2 + expression-test/expression_test_runner.cpp | 110 +----------------------- expression-test/test_runner_common.cpp | 131 +++++++++++++++++++++++++++++ expression-test/test_runner_common.hpp | 13 +++ next/expression-test/CMakeLists.txt | 2 + next/render-test/CMakeLists.txt | 2 + render-test/runner.cpp | 115 +------------------------ 8 files changed, 155 insertions(+), 222 deletions(-) create mode 100644 expression-test/test_runner_common.cpp create mode 100644 expression-test/test_runner_common.hpp diff --git a/cmake/expression-test.cmake b/cmake/expression-test.cmake index 6c5b71a4f6..da4f90d751 100644 --- a/cmake/expression-test.cmake +++ b/cmake/expression-test.cmake @@ -3,6 +3,8 @@ add_executable(mbgl-expression-test expression-test/expression_test_parser.cpp expression-test/expression_test_runner.cpp expression-test/expression_test_logger.cpp + expression-test/test_runner_common.cpp + expression-test/test_runner_common.hpp ) if(APPLE) diff --git a/cmake/render-test.cmake b/cmake/render-test.cmake index 7369655630..65240b54f3 100644 --- a/cmake/render-test.cmake +++ b/cmake/render-test.cmake @@ -3,6 +3,8 @@ add_executable(mbgl-render-test render-test/main.cpp render-test/parser.cpp render-test/runner.cpp + expression-test/test_runner_common.cpp + expression-test/test_runner_common.hpp ) if(APPLE) diff --git a/expression-test/expression_test_runner.cpp b/expression-test/expression_test_runner.cpp index e52c9b1186..c8a39f07ce 100644 --- a/expression-test/expression_test_runner.cpp +++ b/expression-test/expression_test_runner.cpp @@ -1,7 +1,8 @@ #include "expression_test_runner.hpp" -#include "expression_test_parser.hpp" #include "expression_test_logger.hpp" +#include "expression_test_parser.hpp" #include "filesystem.hpp" +#include "test_runner_common.hpp" #include @@ -16,113 +17,6 @@ using namespace std::literals; namespace { -// Strip precision for numbers, so that we can compare evaluated results with fixtures. -// Copied from JS expression harness. -Value stripPrecision(const Value& value) { - const double decimalSigFigs = 6; - if (auto num = numericValue(value)) { - if (*num == 0) { - return *num; - } - - const double multiplier = std::pow(10, - std::max(0.0, decimalSigFigs - std::ceil(std::log10(std::fabs(*num))))); - - // We strip precision twice in a row here to avoid cases where - // stripping an already stripped number will modify its value - // due to bad floating point precision luck - // eg `Math.floor(8.16598 * 100000) / 100000` -> 8.16597 - const double firstStrip = std::floor(*num * multiplier) / multiplier; - return std::floor(firstStrip * multiplier) / multiplier; - } - - if (value.is>()) { - std::vector stripped; - const auto& vec = value.get>(); - stripped.reserve(vec.size()); - for (const auto& val : vec) { - stripped.emplace_back(stripPrecision(val)); - } - return stripped; - } else if (value.is>()) { - std::unordered_map stripped; - const auto& map = value.get>(); - for (const auto& pair : map) { - stripped.emplace(pair.first, stripPrecision(pair.second)); - } - return stripped; - } - - return value; -} - -bool deepEqual(const Value& a, const Value& b) { - const auto& anum = numericValue(a); - const auto& bnum = numericValue(b); - if (anum && bnum) { - return stripPrecision(*anum) == stripPrecision(*bnum); - } - - if (a.which() != b.which()) { - return false; - } - - if (a.is>()) { - const auto& avec = a.get>(); - const auto& bvec = b.get>(); - if (avec.size() != bvec.size()) { - return false; - } - for (std::size_t i = 0; i < avec.size(); ++i) { - if (!deepEqual(avec[i], bvec[i])) { - return false; - } - } - return true; - } - - if (a.is>()) { - const auto& amap = a.get>(); - const auto& bmap = b.get>(); - if (amap.size() != bmap.size()) { - return false; - } - for (const auto& pair : amap) { - auto it = bmap.find(pair.first); - if (it == bmap.end()) { - return false; - } - if (!deepEqual(pair.second, it->second)) { - return false; - } - } - return true; - } - - return a == b; -} - -bool deepEqual(const optional& a, const optional& b) { - if ((a && !b) || (!a && b)) { - return false; - } - - if (a && b) { - return deepEqual(*a, *b); - } - - return true; -} - -std::vector tokenize(std::string str) { - std::vector tokens; - std::regex re("\n"); - std::copy(std::regex_token_iterator(str.begin(), str.end(), re, -1), - std::regex_token_iterator(), - std::back_inserter(tokens)); - return tokens; -} - std::string simpleDiff(const Value& result, const Value& expected) { std::vector resultTokens {tokenize(toJSON(result, 2, true))}; std::vector expectedTokens {tokenize(toJSON(expected, 2, true))}; diff --git a/expression-test/test_runner_common.cpp b/expression-test/test_runner_common.cpp new file mode 100644 index 0000000000..745ef9fced --- /dev/null +++ b/expression-test/test_runner_common.cpp @@ -0,0 +1,131 @@ +#include "test_runner_common.hpp" + +#include +#include + +using namespace mbgl; + +// Strip precision for numbers, so that we can compare evaluated results with fixtures. +// Copied from JS expression harness. +Value stripPrecision(const Value& value) { + const double decimalSigFigs = 6; + if (auto num = numericValue(value)) { + if (*num == 0) { + return *num; + } + + const double multiplier = std::pow(10, std::max(0.0, decimalSigFigs - std::ceil(std::log10(std::fabs(*num))))); + + // We strip precision twice in a row here to avoid cases where + // stripping an already stripped number will modify its value + // due to bad floating point precision luck + // eg `Math.floor(8.16598 * 100000) / 100000` -> 8.16597 + const double firstStrip = std::floor(*num * multiplier) / multiplier; + return std::floor(firstStrip * multiplier) / multiplier; + } + + if (value.is>()) { + std::vector stripped; + const auto& vec = value.get>(); + stripped.reserve(vec.size()); + for (const auto& val : vec) { + stripped.emplace_back(stripPrecision(val)); + } + return stripped; + } else if (value.is>()) { + std::unordered_map stripped; + const auto& map = value.get>(); + for (const auto& pair : map) { + stripped.emplace(pair.first, stripPrecision(pair.second)); + } + return stripped; + } + + return value; +} + +std::vector tokenize(std::string str) { + std::vector tokens; + std::regex re("\n"); + std::copy(std::regex_token_iterator(str.begin(), str.end(), re, -1), + std::regex_token_iterator(), + std::back_inserter(tokens)); + return tokens; +} + +bool deepEqual(const Value& a, const Value& b) { + const auto& anum = numericValue(a); + const auto& bnum = numericValue(b); + if (anum && bnum) { + return stripPrecision(*anum) == stripPrecision(*bnum); + } + + if (a.which() != b.which()) { + return false; + } + + if (a.getArray() && b.getArray()) { + const auto& avec = *a.getArray(); + const auto& bvec = *b.getArray(); + if (avec.size() != bvec.size()) { + return false; + } + for (std::size_t i = 0; i < avec.size(); ++i) { + if (!deepEqual(avec[i], bvec[i])) { + return false; + } + } + return true; + } + + if (a.getObject() && b.getObject()) { + const auto& amap = *a.getObject(); + const auto& bmap = *b.getObject(); + if (amap.size() != bmap.size()) { + return false; + } + for (const auto& pair : amap) { + auto it = bmap.find(pair.first); + if (it == bmap.end()) { + return false; + } + if (!deepEqual(pair.second, it->second)) { + return false; + } + } + return true; + } + + if (a == b) { + return true; + } + + if (a.getString() && b.getString()) { + const auto& strA = *a.getString(); + const auto& strB = *b.getString(); + if (strA == strB) { + return true; + } + + try { + double numA = std::stod(strA); + double numB = std::stod(strB); + return stripPrecision(numA) == stripPrecision(numB); + } catch (...) { + } + } + + return false; +} + +bool deepEqual(const optional& a, const optional& b) { + if ((a && !b) || (!a && b)) { + return false; + } + + if (a && b) { + return deepEqual(*a, *b); + } + + return true; +} diff --git a/expression-test/test_runner_common.hpp b/expression-test/test_runner_common.hpp new file mode 100644 index 0000000000..b30d1a145c --- /dev/null +++ b/expression-test/test_runner_common.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include +#include + +using namespace mbgl; + +Value stripPrecision(const Value& value); +std::vector tokenize(std::string str); +bool deepEqual(const Value& a, const Value& b); +bool deepEqual(const optional& a, const optional& b); diff --git a/next/expression-test/CMakeLists.txt b/next/expression-test/CMakeLists.txt index 1713f0b655..f7d694b054 100644 --- a/next/expression-test/CMakeLists.txt +++ b/next/expression-test/CMakeLists.txt @@ -6,6 +6,8 @@ add_executable( ${MBGL_ROOT}/expression-test/expression_test_parser.hpp ${MBGL_ROOT}/expression-test/expression_test_runner.cpp ${MBGL_ROOT}/expression-test/expression_test_runner.hpp + ${MBGL_ROOT}/expression-test/test_runner_common.cpp + ${MBGL_ROOT}/expression-test/test_runner_common.hpp ${MBGL_ROOT}/expression-test/main.cpp ) diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 6edd11ca95..5aadd0f859 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -9,6 +9,8 @@ add_executable( ${MBGL_ROOT}/render-test/parser.hpp ${MBGL_ROOT}/render-test/runner.cpp ${MBGL_ROOT}/render-test/runner.hpp + ${MBGL_ROOT}/expression-test/test_runner_common.cpp + ${MBGL_ROOT}/expression-test/test_runner_common.hpp ) target_compile_definitions( diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 868e1a9a32..4d4b586a17 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -19,6 +19,7 @@ #include +#include <../expression-test/test_runner_common.hpp> #include "allocation_index.hpp" #include "metadata.hpp" #include "parser.hpp" @@ -26,7 +27,6 @@ #include #include -#include #include #include @@ -47,119 +47,6 @@ const std::vector& TestRunner::getPlatformExpectationsPaths() { return result; } -// Strip precision for numbers, so that we can compare evaluated results with fixtures. -// Copied from JS expression harness. -Value stripPrecision(const Value& value) { - const double decimalSigFigs = 6; - if (auto num = numericValue(value)) { - if (*num == 0) { - return *num; - } - - const double multiplier = std::pow(10, std::max(0.0, decimalSigFigs - std::ceil(std::log10(std::fabs(*num))))); - - // We strip precision twice in a row here to avoid cases where - // stripping an already stripped number will modify its value - // due to bad floating point precision luck - // eg `Math.floor(8.16598 * 100000) / 100000` -> 8.16597 - const double firstStrip = std::floor(*num * multiplier) / multiplier; - return std::floor(firstStrip * multiplier) / multiplier; - } - - if (value.getArray()) { - std::vector stripped; - const auto& vec = *value.getArray(); - stripped.reserve(vec.size()); - for (const auto& val : vec) { - stripped.emplace_back(stripPrecision(val)); - } - return stripped; - } else if (value.getObject()) { - std::unordered_map stripped; - const auto& map = *value.getObject(); - for (const auto& pair : map) { - stripped.emplace(pair.first, stripPrecision(pair.second)); - } - return stripped; - } - - return value; -} - -bool deepEqual(const Value& a, const Value& b) { - const auto& anum = numericValue(a); - const auto& bnum = numericValue(b); - if (anum && bnum) { - return stripPrecision(*anum) == stripPrecision(*bnum); - } - - if (a.which() != b.which()) { - return false; - } - - if (a.getArray() && b.getArray()) { - const auto& avec = *a.getArray(); - const auto& bvec = *b.getArray(); - if (avec.size() != bvec.size()) { - return false; - } - for (std::size_t i = 0; i < avec.size(); ++i) { - if (!deepEqual(avec[i], bvec[i])) { - return false; - } - } - return true; - } - - if (a.getObject() && b.getObject()) { - const auto& amap = *a.getObject(); - const auto& bmap = *b.getObject(); - if (amap.size() != bmap.size()) { - return false; - } - for (const auto& pair : amap) { - auto it = bmap.find(pair.first); - if (it == bmap.end()) { - return false; - } - if (!deepEqual(pair.second, it->second)) { - return false; - } - } - return true; - } - - if (a == b) { - return true; - } - - if (a.getString() && b.getString()) { - const auto& strA = *a.getString(); - const auto& strB = *b.getString(); - if (strA == strB) { - return true; - } - - try { - double numA = std::stod(strA); - double numB = std::stod(strB); - return stripPrecision(numA) == stripPrecision(numB); - } catch (...) { - } - } - - return false; -} - -std::vector tokenize(std::string str) { - std::vector tokens; - std::regex re("\n"); - std::copy(std::regex_token_iterator(str.begin(), str.end(), re, -1), - std::regex_token_iterator(), - std::back_inserter(tokens)); - return tokens; -} - std::string simpleDiff(const Value& result, const Value& expected) { std::vector resultTokens{tokenize(toJSON(result, 2, false))}; std::vector expectedTokens{tokenize(toJSON(expected, 2, false))}; -- cgit v1.2.1 From 7139abdbf546ca4010d874bfd64f72e6f2e2cdcf Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Tue, 8 Oct 2019 16:21:46 +0300 Subject: [android] Expose pre-fetching zoom delta. (#15769) * [android] Expose pre-fetching zoom delta. * [android] Fix Clang format. * [android] Add MapboxMap unit test. * [android] Add prefetching zoom delta into MapboxMapOptions. * [android] Deprecate setPrefetchesTiles to migrate to setPrefetchZoomDelta. * [android] Deprecate getPrefetchesTiles() and migrate to setPrefetchZoomDelta(). * [android] Add unit test to NativeMapViewTest. * [android] Add IntRange annotation to getPrefetchZoomDelta. --- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 38 +++- .../mapbox/mapboxsdk/maps/MapboxMapOptions.java | 41 +++++ .../java/com/mapbox/mapboxsdk/maps/NativeMap.java | 6 + .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 23 +++ .../src/main/res-public/values/public.xml | 1 + .../src/main/res/values/attrs.xml | 1 + .../mapboxsdk/maps/MapboxMapOptionsTest.java | 10 + .../com/mapbox/mapboxsdk/maps/MapboxMapTest.kt | 12 ++ .../com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt | 17 ++ platform/android/src/native_map_view.cpp | 201 +++++++++++---------- platform/android/src/native_map_view.hpp | 4 + 11 files changed, 260 insertions(+), 94 deletions(-) mode change 100755 => 100644 platform/android/src/native_map_view.cpp diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index acd5093dad..8f4cb9438c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -6,6 +6,7 @@ import android.graphics.PointF; import android.graphics.RectF; import android.os.Bundle; import android.support.annotation.FloatRange; +import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Size; @@ -246,12 +247,16 @@ public final class MapboxMap { // Style /** - * Sets tile pre-fetching from MapboxOptions. + * Sets tile pre-fetching zoom delta from MapboxOptions. * * @param options the options object */ private void setPrefetchesTiles(@NonNull MapboxMapOptions options) { - setPrefetchesTiles(options.getPrefetchesTiles()); + if (!options.getPrefetchesTiles()) { + setPrefetchZoomDelta(0); + } else { + setPrefetchZoomDelta(options.getPrefetchZoomDelta()); + } } /** @@ -259,7 +264,9 @@ public final class MapboxMap { * tile is rendered as soon as possible at the expense of a little bandwidth. * * @param enable true to enable + * @deprecated Use {@link #setPrefetchZoomDelta(int)} instead. */ + @Deprecated public void setPrefetchesTiles(boolean enable) { nativeMapView.setPrefetchTiles(enable); } @@ -269,11 +276,38 @@ public final class MapboxMap { * * @return true if enabled * @see MapboxMap#setPrefetchesTiles(boolean) + * @deprecated Use {@link #getPrefetchZoomDelta()} instead. */ + @Deprecated public boolean getPrefetchesTiles() { return nativeMapView.getPrefetchTiles(); } + /** + * Set the tile pre-fetching zoom delta. Pre-fetching makes sure that a low-resolution + * tile at the (current_zoom_level - delta) is rendered as soon as possible at the + * expense of a little bandwidth. + * Note: This operation will override the MapboxMapOptions#setPrefetchesTiles(boolean) + * Setting zoom delta to 0 will disable pre-fetching. + * Default zoom delta is 4. + * + * @param delta zoom delta + */ + public void setPrefetchZoomDelta(@IntRange(from = 0) int delta) { + nativeMapView.setPrefetchZoomDelta(delta); + } + + /** + * Check current pre-fetching zoom delta. + * + * @return current zoom delta. + * @see MapboxMap#setPrefetchZoomDelta(int) + */ + @IntRange(from = 0) + public int getPrefetchZoomDelta() { + return nativeMapView.getPrefetchZoomDelta(); + } + // // MinZoom // diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 6cd3271d12..8277568707 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -8,6 +8,7 @@ import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.ColorInt; +import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -70,6 +71,7 @@ public class MapboxMapOptions implements Parcelable { private boolean quickZoomGesturesEnabled = true; private boolean prefetchesTiles = true; + private int prefetchZoomDelta = 4; private boolean zMediaOverlay = false; private boolean localIdeographFontFamilyEnabled = true; @@ -134,6 +136,7 @@ public class MapboxMapOptions implements Parcelable { textureMode = in.readByte() != 0; translucentTextureSurface = in.readByte() != 0; prefetchesTiles = in.readByte() != 0; + prefetchZoomDelta = in.readInt(); zMediaOverlay = in.readByte() != 0; localIdeographFontFamilyEnabled = in.readByte() != 0; localIdeographFontFamily = in.readString(); @@ -257,6 +260,8 @@ public class MapboxMapOptions implements Parcelable { typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureTranslucentSurface, false)); mapboxMapOptions.setPrefetchesTiles( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true)); + mapboxMapOptions.setPrefetchZoomDelta( + typedArray.getInt(R.styleable.mapbox_MapView_mapbox_prefetchZoomDelta, 4)); mapboxMapOptions.renderSurfaceOnTop( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false)); @@ -633,13 +638,32 @@ public class MapboxMapOptions implements Parcelable { * * @param enable true to enable * @return This + * @deprecated Use {@link #setPrefetchZoomDelta(int)} instead. */ + @Deprecated @NonNull public MapboxMapOptions setPrefetchesTiles(boolean enable) { this.prefetchesTiles = enable; return this; } + /** + * Set the tile pre-fetching zoom delta. Pre-fetching makes sure that a low-resolution + * tile at the (current_zoom_level - delta) is rendered as soon as possible at the + * expense of a little bandwidth. + * Note: This operation will override the MapboxMapOptions#setPrefetchesTiles(boolean) + * Setting zoom delta to 0 will disable pre-fetching. + * Default zoom delta is 4. + * + * @param delta zoom delta + * @return This + */ + @NonNull + public MapboxMapOptions setPrefetchZoomDelta(@IntRange(from = 0) int delta) { + this.prefetchZoomDelta = delta; + return this; + } + /** * Enable cross-source symbol collision detection, defaults to true. *

@@ -721,11 +745,23 @@ public class MapboxMapOptions implements Parcelable { * Check whether tile pre-fetching is enabled. * * @return true if enabled + * @deprecated Use {@link #getPrefetchZoomDelta()} instead. */ + @Deprecated public boolean getPrefetchesTiles() { return prefetchesTiles; } + /** + * Check current pre-fetching zoom delta. + * + * @return current zoom delta. + */ + @IntRange(from = 0) + public int getPrefetchZoomDelta() { + return prefetchZoomDelta; + } + /** * Check whether cross-source symbol collision detection is enabled. * @@ -1081,6 +1117,7 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (textureMode ? 1 : 0)); dest.writeByte((byte) (translucentTextureSurface ? 1 : 0)); dest.writeByte((byte) (prefetchesTiles ? 1 : 0)); + dest.writeInt(prefetchZoomDelta); dest.writeByte((byte) (zMediaOverlay ? 1 : 0)); dest.writeByte((byte) (localIdeographFontFamilyEnabled ? 1 : 0)); dest.writeString(localIdeographFontFamily); @@ -1175,6 +1212,9 @@ public class MapboxMapOptions implements Parcelable { if (prefetchesTiles != options.prefetchesTiles) { return false; } + if (prefetchZoomDelta != options.prefetchZoomDelta) { + return false; + } if (zMediaOverlay != options.zMediaOverlay) { return false; } @@ -1231,6 +1271,7 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (textureMode ? 1 : 0); result = 31 * result + (translucentTextureSurface ? 1 : 0); result = 31 * result + (prefetchesTiles ? 1 : 0); + result = 31 * result + prefetchZoomDelta; result = 31 * result + (zMediaOverlay ? 1 : 0); result = 31 * result + (localIdeographFontFamilyEnabled ? 1 : 0); result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java index 7f3017c7ae..c805dcddb0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java @@ -6,6 +6,7 @@ import android.graphics.RectF; import android.support.annotation.IntRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; + import com.mapbox.geojson.Feature; import com.mapbox.geojson.Geometry; import com.mapbox.mapboxsdk.annotations.Marker; @@ -214,6 +215,11 @@ interface NativeMap { boolean getPrefetchTiles(); + void setPrefetchZoomDelta(@IntRange(from = 0) int delta); + + @IntRange(from = 0) + int getPrefetchZoomDelta(); + void setGestureInProgress(boolean inProgress); float getPixelRatio(); 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 c844133f41..75ca5edfca 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 @@ -724,6 +724,23 @@ final class NativeMapView implements NativeMap { return nativeGetPrefetchTiles(); } + @Override + public void setPrefetchZoomDelta(@IntRange(from = 0) int delta) { + if (checkState("nativeSetPrefetchZoomDelta")) { + return; + } + nativeSetPrefetchZoomDelta(delta); + } + + @Override + @IntRange(from = 0) + public int getPrefetchZoomDelta() { + if (checkState("nativeGetPrefetchZoomDelta")) { + return 0; + } + return nativeGetPrefetchZoomDelta(); + } + // Runtime style Api @Override @@ -1383,6 +1400,12 @@ final class NativeMapView implements NativeMap { @Keep private native boolean nativeGetPrefetchTiles(); + @Keep + private native void nativeSetPrefetchZoomDelta(int delta); + + @Keep + private native int nativeGetPrefetchZoomDelta(); + @Override public long getNativePtr() { return nativePtr; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 60a1efc771..36071cc2a7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -69,6 +69,7 @@ + diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index ff8a32ac64..137f72f8d2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -109,6 +109,7 @@ + diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index 6978afcf1f..c46e6e3190 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -167,6 +167,16 @@ public class MapboxMapOptionsTest { assertFalse(new MapboxMapOptions().setPrefetchesTiles(false).getPrefetchesTiles()); } + @Test + public void testPrefetchZoomDelta() { + // Default value + assertEquals(4, new MapboxMapOptions().getPrefetchZoomDelta()); + + // Check mutations + assertEquals(5, new MapboxMapOptions().setPrefetchZoomDelta(5).getPrefetchZoomDelta()); + } + + @Test public void testCrossSourceCollisions() { // Default value diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt index deb5f603c8..6647fe5595 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.kt @@ -126,6 +126,18 @@ class MapboxMapTest { verify { nativeMapView.prefetchTiles = true } } + @Test + fun testGetPrefetchZoomDelta() { + every { nativeMapView.prefetchZoomDelta } answers { 3 } + assertEquals(3, mapboxMap.prefetchZoomDelta) + } + + @Test + fun testSetPrefetchZoomDelta() { + mapboxMap.prefetchZoomDelta = 2 + verify { nativeMapView.prefetchZoomDelta = 2 } + } + @Test fun testCameraForLatLngBounds() { val bounds = LatLngBounds.Builder().include(LatLng()).include(LatLng(1.0, 1.0)).build() diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt index 9117271292..dc313b5f64 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt @@ -221,6 +221,23 @@ class NativeMapViewTest : AppCenter() { assertEquals("Flag should match", expected, actual) } + @Test + @UiThreadTest + fun testPrefetchZoomDelta() { + val expected = 2 + nativeMapView.prefetchZoomDelta = 2 + val actual = nativeMapView.prefetchZoomDelta + assertEquals("Prefetch zoom delta should match", expected, actual) + } + + @Test + @UiThreadTest + fun testPrefetchZoomDeltaDefault() { + val expected = 4 + val actual = nativeMapView.prefetchZoomDelta + assertEquals("Prefetch zoom delta should match", expected, actual) + } + @Test @UiThreadTest fun testSetContentPadding() { diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp old mode 100755 new mode 100644 index 7b87693cf5..8cb637fa38 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -40,19 +40,19 @@ #include "style/conversion/filter.hpp" #include "geojson/feature.hpp" -#include "jni.hpp" -#include "attach_env.hpp" -#include "map_renderer.hpp" #include "android_renderer_frontend.hpp" -#include "file_source.hpp" +#include "attach_env.hpp" #include "bitmap.hpp" -#include "run_loop_impl.hpp" -#include "java/util.hpp" +#include "bitmap_factory.hpp" +#include "file_source.hpp" #include "geometry/lat_lng_bounds.hpp" +#include "java/util.hpp" +#include "jni.hpp" #include "map/camera_position.hpp" -#include "map/image.hpp" +#include "map/image.hpp" +#include "map_renderer.hpp" +#include "run_loop_impl.hpp" #include "style/light.hpp" -#include "bitmap_factory.hpp" namespace mbgl { namespace android { @@ -1050,6 +1050,14 @@ jni::jboolean NativeMapView::getPrefetchTiles(JNIEnv&) { return jni::jboolean(map->getPrefetchZoomDelta() > 0); } +void NativeMapView::setPrefetchZoomDelta(JNIEnv&, jni::jint delta) { + map->setPrefetchZoomDelta(uint8_t(delta)); +} + +jni::jint NativeMapView::getPrefetchZoomDelta(JNIEnv&) { + return jni::jint(map->getPrefetchZoomDelta()); +} + mbgl::Map& NativeMapView::getMap() { return *map; } @@ -1063,90 +1071,99 @@ void NativeMapView::registerNative(jni::JNIEnv& env) { #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod(name) // Register the peer - jni::RegisterNativePeer(env, javaClass, "nativePtr", - jni::MakePeer&, const jni::Object&, const jni::Object&, jni::jfloat, jni::jboolean>, - "nativeInitialize", - "nativeDestroy", - METHOD(&NativeMapView::resizeView, "nativeResizeView"), - METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), - METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), - METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), - METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), - METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), - METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), - METHOD(&NativeMapView::moveBy, "nativeMoveBy"), - METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), - METHOD(&NativeMapView::easeTo, "nativeEaseTo"), - METHOD(&NativeMapView::flyTo, "nativeFlyTo"), - METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), - METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), - METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), - METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), - METHOD(&NativeMapView::setReachability, "nativeSetReachability"), - METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), - METHOD(&NativeMapView::getPitch, "nativeGetPitch"), - METHOD(&NativeMapView::setPitch, "nativeSetPitch"), - METHOD(&NativeMapView::getZoom, "nativeGetZoom"), - METHOD(&NativeMapView::setZoom, "nativeSetZoom"), - METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), - METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), - METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), - METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), - METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), - METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), - METHOD(&NativeMapView::setBearing, "nativeSetBearing"), - METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), - METHOD(&NativeMapView::getBearing, "nativeGetBearing"), - METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), - METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), - METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), - METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), - METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), - METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), - METHOD(&NativeMapView::setDebug, "nativeSetDebug"), - METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"), - METHOD(&NativeMapView::getDebug, "nativeGetDebug"), - METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), - METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), - METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), - METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), - METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), - METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), - METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), - METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), - METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), - METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), - METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), - METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), - METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), - METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), - METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), - METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), - METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), - METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), - METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), - METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), - METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), - METHOD(&NativeMapView::getLight, "nativeGetLight"), - METHOD(&NativeMapView::getLayers, "nativeGetLayers"), - METHOD(&NativeMapView::getLayer, "nativeGetLayer"), - METHOD(&NativeMapView::addLayer, "nativeAddLayer"), - METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), - METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), - METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), - METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), - METHOD(&NativeMapView::getSources, "nativeGetSources"), - METHOD(&NativeMapView::getSource, "nativeGetSource"), - METHOD(&NativeMapView::addSource, "nativeAddSource"), - METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), - METHOD(&NativeMapView::addImage, "nativeAddImage"), - METHOD(&NativeMapView::addImages, "nativeAddImages"), - METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), - METHOD(&NativeMapView::getImage, "nativeGetImage"), - METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), - METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), - METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles") - ); + jni::RegisterNativePeer( + env, + javaClass, + "nativePtr", + jni::MakePeer&, + const jni::Object&, + const jni::Object&, + jni::jfloat, + jni::jboolean>, + "nativeInitialize", + "nativeDestroy", + METHOD(&NativeMapView::resizeView, "nativeResizeView"), + METHOD(&NativeMapView::getStyleUrl, "nativeGetStyleUrl"), + METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), + METHOD(&NativeMapView::getStyleJson, "nativeGetStyleJson"), + METHOD(&NativeMapView::setStyleJson, "nativeSetStyleJson"), + METHOD(&NativeMapView::cancelTransitions, "nativeCancelTransitions"), + METHOD(&NativeMapView::setGestureInProgress, "nativeSetGestureInProgress"), + METHOD(&NativeMapView::moveBy, "nativeMoveBy"), + METHOD(&NativeMapView::jumpTo, "nativeJumpTo"), + METHOD(&NativeMapView::easeTo, "nativeEaseTo"), + METHOD(&NativeMapView::flyTo, "nativeFlyTo"), + METHOD(&NativeMapView::getLatLng, "nativeGetLatLng"), + METHOD(&NativeMapView::setLatLng, "nativeSetLatLng"), + METHOD(&NativeMapView::getCameraForLatLngBounds, "nativeGetCameraForLatLngBounds"), + METHOD(&NativeMapView::getCameraForGeometry, "nativeGetCameraForGeometry"), + METHOD(&NativeMapView::setReachability, "nativeSetReachability"), + METHOD(&NativeMapView::resetPosition, "nativeResetPosition"), + METHOD(&NativeMapView::getPitch, "nativeGetPitch"), + METHOD(&NativeMapView::setPitch, "nativeSetPitch"), + METHOD(&NativeMapView::getZoom, "nativeGetZoom"), + METHOD(&NativeMapView::setZoom, "nativeSetZoom"), + METHOD(&NativeMapView::resetZoom, "nativeResetZoom"), + METHOD(&NativeMapView::setMinZoom, "nativeSetMinZoom"), + METHOD(&NativeMapView::getMinZoom, "nativeGetMinZoom"), + METHOD(&NativeMapView::setMaxZoom, "nativeSetMaxZoom"), + METHOD(&NativeMapView::getMaxZoom, "nativeGetMaxZoom"), + METHOD(&NativeMapView::rotateBy, "nativeRotateBy"), + METHOD(&NativeMapView::setBearing, "nativeSetBearing"), + METHOD(&NativeMapView::setBearingXY, "nativeSetBearingXY"), + METHOD(&NativeMapView::getBearing, "nativeGetBearing"), + METHOD(&NativeMapView::resetNorth, "nativeResetNorth"), + METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"), + METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"), + METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"), + METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"), + METHOD(&NativeMapView::addMarkers, "nativeAddMarkers"), + METHOD(&NativeMapView::setDebug, "nativeSetDebug"), + METHOD(&NativeMapView::cycleDebugOptions, "nativeCycleDebugOptions"), + METHOD(&NativeMapView::getDebug, "nativeGetDebug"), + METHOD(&NativeMapView::isFullyLoaded, "nativeIsFullyLoaded"), + METHOD(&NativeMapView::onLowMemory, "nativeOnLowMemory"), + METHOD(&NativeMapView::getMetersPerPixelAtLatitude, "nativeGetMetersPerPixelAtLatitude"), + METHOD(&NativeMapView::projectedMetersForLatLng, "nativeProjectedMetersForLatLng"), + METHOD(&NativeMapView::pixelForLatLng, "nativePixelForLatLng"), + METHOD(&NativeMapView::latLngForProjectedMeters, "nativeLatLngForProjectedMeters"), + METHOD(&NativeMapView::latLngForPixel, "nativeLatLngForPixel"), + METHOD(&NativeMapView::addPolylines, "nativeAddPolylines"), + METHOD(&NativeMapView::addPolygons, "nativeAddPolygons"), + METHOD(&NativeMapView::updatePolyline, "nativeUpdatePolyline"), + METHOD(&NativeMapView::updatePolygon, "nativeUpdatePolygon"), + METHOD(&NativeMapView::removeAnnotations, "nativeRemoveAnnotations"), + METHOD(&NativeMapView::addAnnotationIcon, "nativeAddAnnotationIcon"), + METHOD(&NativeMapView::removeAnnotationIcon, "nativeRemoveAnnotationIcon"), + METHOD(&NativeMapView::getTopOffsetPixelsForAnnotationSymbol, "nativeGetTopOffsetPixelsForAnnotationSymbol"), + METHOD(&NativeMapView::getTransitionOptions, "nativeGetTransitionOptions"), + METHOD(&NativeMapView::setTransitionOptions, "nativeSetTransitionOptions"), + METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"), + METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"), + METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"), + METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"), + METHOD(&NativeMapView::getLight, "nativeGetLight"), + METHOD(&NativeMapView::getLayers, "nativeGetLayers"), + METHOD(&NativeMapView::getLayer, "nativeGetLayer"), + METHOD(&NativeMapView::addLayer, "nativeAddLayer"), + METHOD(&NativeMapView::addLayerAbove, "nativeAddLayerAbove"), + METHOD(&NativeMapView::addLayerAt, "nativeAddLayerAt"), + METHOD(&NativeMapView::removeLayerAt, "nativeRemoveLayerAt"), + METHOD(&NativeMapView::removeLayer, "nativeRemoveLayer"), + METHOD(&NativeMapView::getSources, "nativeGetSources"), + METHOD(&NativeMapView::getSource, "nativeGetSource"), + METHOD(&NativeMapView::addSource, "nativeAddSource"), + METHOD(&NativeMapView::removeSource, "nativeRemoveSource"), + METHOD(&NativeMapView::addImage, "nativeAddImage"), + METHOD(&NativeMapView::addImages, "nativeAddImages"), + METHOD(&NativeMapView::removeImage, "nativeRemoveImage"), + METHOD(&NativeMapView::getImage, "nativeGetImage"), + METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"), + METHOD(&NativeMapView::setPrefetchTiles, "nativeSetPrefetchTiles"), + METHOD(&NativeMapView::getPrefetchTiles, "nativeGetPrefetchTiles"), + METHOD(&NativeMapView::setPrefetchZoomDelta, "nativeSetPrefetchZoomDelta"), + METHOD(&NativeMapView::getPrefetchZoomDelta, "nativeGetPrefetchZoomDelta")); } } // namespace android diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index ba2178022e..5a340d1287 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -235,6 +235,10 @@ public: jni::jboolean getPrefetchTiles(JNIEnv&); + void setPrefetchZoomDelta(JNIEnv&, jni::jint); + + jni::jint getPrefetchZoomDelta(JNIEnv&); + mbgl::Map& getMap(); private: -- cgit v1.2.1 From 563f9d0534cf6540652121f468cb0526148d70b9 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Tue, 8 Oct 2019 17:49:45 -0400 Subject: [ios] Skip metrics.sh step (#15779) --- circle.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 6813aa6c9f..0046dc7fa0 100644 --- a/circle.yml +++ b/circle.yml @@ -1446,8 +1446,11 @@ jobs: platform/ios/scripts/deploy-to-cocoapods.sh fi - run: - name: Record size - command: platform/ios/scripts/metrics.sh + name: Record size + command: | + echo "Skipping Record size step" + # Skipping due to https://github.com/mapbox/mapbox-gl-native/issues/15751 + #platform/ios/scripts/metrics.sh - run: name: Trigger metrics command: | -- cgit v1.2.1 From d0281e3ca4686ca52b1b4d886dad4e8de27bdcfa Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 8 Oct 2019 16:27:04 -0700 Subject: node package improvements (#15748) * node package improvements * npm run test-suite does not do anything anymore --- .npmignore | 32 ++++++++++++++++++++++++++++++++ cmake/node.cmake | 4 ++-- package.json | 2 +- platform/node/DEVELOPING.md | 21 +++++++++++---------- platform/node/README.md | 6 +++--- 5 files changed, 49 insertions(+), 16 deletions(-) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000000..d2490da83f --- /dev/null +++ b/.npmignore @@ -0,0 +1,32 @@ +Makefile +CmakeLists.txt +*yml +build +cmake +misc +.* +*tgz +benchmark +expression-test +cloudformation +bin +vendor +include +mason_packages +mapbox-gl-js +test +lib +next +src +scripts +render-test +platform/android +platform/darwin +platform/default +platform/glfw +platform/ios +platform/linux +platform/macos +platform/qt +platform/node/symbol-list +platform/node/version-script \ No newline at end of file diff --git a/cmake/node.cmake b/cmake/node.cmake index a791d99b42..edea4df71b 100644 --- a/cmake/node.cmake +++ b/cmake/node.cmake @@ -20,8 +20,8 @@ create_source_groups(mbgl-loop-node) add_node_module(mbgl-node INSTALL_PATH "lib/{node_abi}/mbgl.node" - NAN_VERSION "2.10.0" - + NAN_VERSION "2.14.0" + # Don't build for Node 4.x, 5.x, 7.x, 9.x, 11.x and 12.x # See https://nodejs.org/en/download/releases/ for mapping of Node version to ABI number. # Changes to this property should happen in tandem with updates to the version targets diff --git a/package.json b/package.json index 9b11a039cd..90ec89de71 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "node": ">=6" }, "scripts": { - "install": "node-pre-gyp install --fallback-to-build=false || make node", + "install": "node-pre-gyp install --fallback-to-build=false", "test": "tape platform/node/test/js/**/*.test.js", "test-memory": "node --expose-gc platform/node/test/memory.test.js", "test-expressions": "node -r esm platform/node/test/expression.test.js", diff --git a/platform/node/DEVELOPING.md b/platform/node/DEVELOPING.md index 3d07253ee3..1466052155 100644 --- a/platform/node/DEVELOPING.md +++ b/platform/node/DEVELOPING.md @@ -8,27 +8,28 @@ To develop these bindings, you’ll need to build them from source. Building req the [macOS](../macos/INSTALL.md#requirements) or [Linux](../linux/README.md#prerequisites) install documentation, depending on the target platform. -To compile the Node.js bindings and install module dependencies, from the repository root directory, run: +To compile the Node.js bindings and install module dependencies, from the repository root directory, first run: - npm install --build-from-source +``` +make distclean +``` -To recompile just the C++ code while developing, run `make node`. +If you are rebuilding after time has passed. -To create an Xcode project and use a GUI debugger in the case of a crash, run `make xnode`. +Then do: + +```bash +make node +``` ## Testing To test the Node.js bindings: -``` +```bash npm test ``` -To run the visual render test suite: - -``` -npm run test-suite -``` ## Merging your pull request diff --git a/platform/node/README.md b/platform/node/README.md index 7273c0813a..859172108b 100644 --- a/platform/node/README.md +++ b/platform/node/README.md @@ -9,7 +9,7 @@ Requires a modern C++ runtime that supports C++14. By default, installs binaries. On these platforms no additional dependencies are needed. - 64 bit macOS or 64 bit Linux -- Node.js v4.x _(note: v5+ is known to have issues)_ +- Node.js v10.x Run: @@ -168,9 +168,9 @@ var map = new mbgl.Map({ if (res.headers.modified) { response.modified = new Date(res.headers.modified); } if (res.headers.expires) { response.expires = new Date(res.headers.expires); } if (res.headers.etag) { response.etag = res.headers.etag; } - + response.data = body; - + callback(null, response); } else { callback(new Error(JSON.parse(body).message)); -- cgit v1.2.1 From b4e0224a5786f1d362b2b6b7e7f536be8bb98981 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 9 Oct 2019 13:26:28 +0300 Subject: [test runner] Fix finding of expected images paths Before this change, the found paths to the expected images erroneously included the path to the `metrics.json` file (if this file was present) leading to raising of an unhandled exception. --- render-test/parser.cpp | 15 ++++++++++++--- render-test/parser.hpp | 3 ++- render-test/runner.cpp | 4 ++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 802c3c7f55..024adf91d1 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -291,9 +291,8 @@ std::string serializeMetrics(const TestMetrics& metrics) { return s.GetString(); } -std::vector readExpectedEntries(const mbgl::filesystem::path& base) { - static const std::regex regex(".*expected.*.png|.*expected.*.json"); - +namespace { +std::vector readExpectedEntries(const std::regex& regex, const mbgl::filesystem::path& base) { std::vector expectedImages; for (const auto& entry : mbgl::filesystem::directory_iterator(base)) { if (entry.is_regular_file()) { @@ -305,7 +304,17 @@ std::vector readExpectedEntries(const mbgl::filesystem::path& base) } return expectedImages; } +} // namespace + +std::vector readExpectedImageEntries(const mbgl::filesystem::path& base) { + static const std::regex regex(".*expected.*.png"); + return readExpectedEntries(regex, base); +} +std::vector readExpectedJSONEntries(const mbgl::filesystem::path& base) { + static const std::regex regex(".*expected.*.json"); + return readExpectedEntries(regex, base); +} ArgumentsTuple parseArguments(int argc, char** argv) { args::ArgumentParser argumentParser("Mapbox GL Test Runner"); diff --git a/render-test/parser.hpp b/render-test/parser.hpp index afa281ad30..3c857b7e1e 100644 --- a/render-test/parser.hpp +++ b/render-test/parser.hpp @@ -18,7 +18,8 @@ JSONReply readJson(const mbgl::filesystem::path&); std::string serializeJsonValue(const mbgl::JSValue&); std::string serializeMetrics(const TestMetrics&); -std::vector readExpectedEntries(const mbgl::filesystem::path& base); +std::vector readExpectedImageEntries(const mbgl::filesystem::path& base); +std::vector readExpectedJSONEntries(const mbgl::filesystem::path& base); TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path); diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 4d4b586a17..5df167431f 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -122,7 +122,7 @@ bool TestRunner::checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, mbgl::filesystem::path expectedMetricsPath; for (auto rit = expectations.rbegin(); rit != expectations.rend(); ++rit) { if (mbgl::filesystem::exists(*rit)) { - expectedJsonPaths = readExpectedEntries(*rit); + expectedJsonPaths = readExpectedJSONEntries(*rit); if (!expectedJsonPaths.empty()) break; } } @@ -206,7 +206,7 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, maybeExpectedMetricsPath.replace_filename("metrics.json"); metadata.expectedMetrics = readExpectedMetrics(maybeExpectedMetricsPath); } - expectedImagesPaths = readExpectedEntries(*rit); + expectedImagesPaths = readExpectedImageEntries(*rit); if (!expectedImagesPaths.empty()) break; } } -- cgit v1.2.1 From 32a73a5be52e5093080523080c39f10a6f9b4cc0 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Wed, 9 Oct 2019 12:41:17 -0700 Subject: [ios] Podspec & changelog updates for v5.5.0-alpha.2 --- platform/ios/CHANGELOG.md | 4 +--- platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec | 2 +- platform/ios/Mapbox-iOS-SDK-stripped.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index a3c4546276..2f3eb809e7 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,14 +2,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. -## master +## 5.5.0 ### Performance improvements * Improved rendering performance for the styles with multiple sources ([#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756)) -## 5.5.0 - ### Other changes * Added `-[MGLMapSnapshotOverlay coordinateForPoint:]` and `-[MGLMapSnapshotOverlay pointForCoordinate:]` to convert between context and map coordinates, mirroring those of `MGLMapSnapshot`. ([#15746](https://github.com/mapbox/mapbox-gl-native/pull/15746)) diff --git a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec index 9d01fb63b3..84ce50bb4f 100644 --- a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec +++ b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '5.5.0-alpha.1' + version = '5.5.0-alpha.2' m.name = 'Mapbox-iOS-SDK-snapshot-dynamic' m.version = "#{version}-snapshot" diff --git a/platform/ios/Mapbox-iOS-SDK-stripped.podspec b/platform/ios/Mapbox-iOS-SDK-stripped.podspec index ff5e503d96..51d7087c63 100644 --- a/platform/ios/Mapbox-iOS-SDK-stripped.podspec +++ b/platform/ios/Mapbox-iOS-SDK-stripped.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '5.5.0-alpha.1' + version = '5.5.0-alpha.2' m.name = 'Mapbox-iOS-SDK-stripped' m.version = "#{version}-stripped" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 44d3ee70a9..c4f686f060 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 = '5.5.0-alpha.1' + version = '5.5.0-alpha.2' m.name = 'Mapbox-iOS-SDK' m.version = version -- cgit v1.2.1 From da490c2b90125bf82fc84b1782a795e48ab5a548 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 9 Oct 2019 13:30:17 -0700 Subject: bump to v5 (#15781) --- package.json | 2 +- platform/node/CHANGELOG.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 90ec89de71..adda5fef5b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mapbox/mapbox-gl-native", - "version": "4.3.0", + "version": "5.0.0", "description": "Renders map tiles with Mapbox GL", "keywords": [ "mapbox", diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md index 84fbff741c..6af55f5d50 100644 --- a/platform/node/CHANGELOG.md +++ b/platform/node/CHANGELOG.md @@ -1,4 +1,6 @@ -# master + +# 5.0.0 +* No longer supporting source-compile fallback ([#15748](https://github.com/mapbox/mapbox-gl-native/pull/15748)) * Add support for feature state APIs. ([#15480](https://github.com/mapbox/mapbox-gl-native/pull/15480)) # 4.3.0 -- cgit v1.2.1 From f62e5b00c98b50e9d9a1e76f4ae5e70129e83ff4 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 9 Oct 2019 16:23:12 +0300 Subject: [core] Introduce Scheduler::makeWeakPtr() --- include/mbgl/actor/scheduler.hpp | 4 ++++ include/mbgl/util/run_loop.hpp | 2 ++ platform/android/src/map_renderer.hpp | 2 ++ platform/qt/src/qmapboxgl_scheduler.hpp | 2 ++ src/mbgl/util/thread_pool.hpp | 3 +++ test/actor/actor.test.cpp | 2 ++ 6 files changed, 15 insertions(+) diff --git a/include/mbgl/actor/scheduler.hpp b/include/mbgl/actor/scheduler.hpp index ca34901cfd..7338c3ab3a 100644 --- a/include/mbgl/actor/scheduler.hpp +++ b/include/mbgl/actor/scheduler.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -35,6 +37,8 @@ public: // Enqueues a function for execution. virtual void schedule(std::function) = 0; + // Makes a weak pointer to this Scheduler. + virtual mapbox::base::WeakPtr makeWeakPtr() = 0; // Set/Get the current Scheduler for this thread static Scheduler* GetCurrent(); diff --git a/include/mbgl/util/run_loop.hpp b/include/mbgl/util/run_loop.hpp index 961573fd87..5cde95a531 100644 --- a/include/mbgl/util/run_loop.hpp +++ b/include/mbgl/util/run_loop.hpp @@ -74,6 +74,7 @@ public: } void schedule(std::function fn) override { invoke(std::move(fn)); } + ::mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } class Impl; @@ -121,6 +122,7 @@ private: std::mutex mutex; std::unique_ptr impl; + ::mapbox::base::WeakPtrFactory weakFactory{this}; }; } // namespace util diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp index 664da20a94..047f1870c7 100644 --- a/platform/android/src/map_renderer.hpp +++ b/platform/android/src/map_renderer.hpp @@ -68,6 +68,7 @@ public: // From Scheduler. Schedules by using callbacks to the // JVM to process the mailbox on the right thread. void schedule(std::function scheduled) override; + mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } void requestRender(); @@ -122,6 +123,7 @@ private: std::atomic destroyed {false}; std::unique_ptr snapshotCallback; + mapbox::base::WeakPtrFactory weakFactory{this}; }; } // namespace android diff --git a/platform/qt/src/qmapboxgl_scheduler.hpp b/platform/qt/src/qmapboxgl_scheduler.hpp index b34dd3d5b8..0b000b9fcc 100644 --- a/platform/qt/src/qmapboxgl_scheduler.hpp +++ b/platform/qt/src/qmapboxgl_scheduler.hpp @@ -19,6 +19,7 @@ public: // mbgl::Scheduler implementation. void schedule(std::function scheduled) final; + mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } void processEvents(); @@ -30,4 +31,5 @@ private: std::mutex m_taskQueueMutex; std::queue> m_taskQueue; + mapbox::base::WeakPtrFactory weakFactory{this}; }; diff --git a/src/mbgl/util/thread_pool.hpp b/src/mbgl/util/thread_pool.hpp index f302e50914..7642f9b4ca 100644 --- a/src/mbgl/util/thread_pool.hpp +++ b/src/mbgl/util/thread_pool.hpp @@ -52,8 +52,11 @@ public: } } + mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } + private: std::array threads; + mapbox::base::WeakPtrFactory weakFactory{this}; static_assert(N > 0, "Thread count must be more than zero."); }; diff --git a/test/actor/actor.test.cpp b/test/actor/actor.test.cpp index 4b152f471a..c2a41fe787 100644 --- a/test/actor/actor.test.cpp +++ b/test/actor/actor.test.cpp @@ -90,6 +90,7 @@ TEST(Actor, DestructionBlocksOnSend) { std::promise promise; std::future future; std::atomic waited; + mapbox::base::WeakPtrFactory weakFactory{this}; TestScheduler(std::promise promise_, std::future future_) : promise(std::move(promise_)), @@ -107,6 +108,7 @@ TEST(Actor, DestructionBlocksOnSend) { std::this_thread::sleep_for(1ms); waited = true; } + mapbox::base::WeakPtr makeWeakPtr() override { return weakFactory.makeWeakPtr(); } }; struct Test { -- cgit v1.2.1 From 76bbc42fa6fedbaef7fc1fdd9412049a62293fd2 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 8 Oct 2019 17:14:37 +0300 Subject: [core] Coalesce requests for the same missing image This commit coalesces the repeated `onStyleImageMissing` calls for the same image. It also simplifies the image manager code. --- src/mbgl/renderer/image_manager.cpp | 54 ++++++++++++++++++++++--------------- src/mbgl/renderer/image_manager.hpp | 18 ++++++++----- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index d001084f92..a776672edd 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -138,8 +138,9 @@ void ImageManager::removeRequestor(ImageRequestor& requestor) { void ImageManager::notifyIfMissingImageAdded() { for (auto it = missingImageRequestors.begin(); it != missingImageRequestors.end();) { - if (it->second.callbacks.empty()) { - notify(*it->first, it->second.pair); + ImageRequestor& requestor = *it->first; + if (!requestor.hasPendingRequests()) { + notify(requestor, it->second); it = missingImageRequestors.erase(it); } else { ++it; @@ -179,28 +180,37 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR if (!missingImages.empty()) { ImageRequestor* requestorPtr = &requestor; - - auto emplaced = missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair { pair, {} }); - assert(emplaced.second); + assert(!missingImageRequestors.count(requestorPtr)); + missingImageRequestors.emplace(requestorPtr, pair); for (const auto& missingImage : missingImages) { assert(observer != nullptr); - requestedImages[missingImage].emplace(&requestor); - auto callback = std::make_unique( - *Scheduler::GetCurrent(), - [this, requestorPtr, missingImage] { - auto requestorIt = missingImageRequestors.find(requestorPtr); - if (requestorIt != missingImageRequestors.end()) { - assert(requestorIt->second.callbacks.find(missingImage) != requestorIt->second.callbacks.end()); - requestorIt->second.callbacks.erase(missingImage); - } - }); - - auto actorRef = callback->self(); - emplaced.first->second.callbacks.emplace(missingImage, std::move(callback)); - observer->onStyleImageMissing(missingImage, [actorRef] { - actorRef.invoke(&Callback::operator()); - }); + + auto existingRequestorsIt = requestedImages.find(missingImage); + if (existingRequestorsIt != requestedImages.end()) { // Already asked client about this image. + if (!existingRequestorsIt->second.empty()) { // Still waiting for the client response. + existingRequestorsIt->second.emplace(requestorPtr); + requestor.addPendingRequest(missingImage); + } + continue; + } + requestedImages[missingImage].emplace(requestorPtr); + requestor.addPendingRequest(missingImage); + auto removePendingRequests = [this, missingImage] { + auto existingRequest = requestedImages.find(missingImage); + if (existingRequest == requestedImages.end()) { + return; + } + + for (auto* req : existingRequest->second) { + req->removePendingRequest(missingImage); + } + }; + + Scheduler& scheduler = *Scheduler::GetCurrent(); + auto callback = [&scheduler, removePendingRequests]() { scheduler.schedule(removePendingRequests); }; + + observer->onStyleImageMissing(missingImage, std::move(callback)); } } else { // Associate requestor with an image that was provided by the client. @@ -230,7 +240,7 @@ void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pai } } - requestor.onImagesAvailable(iconMap, patternMap, std::move(versionMap), pair.second); + requestor.onImagesAvailable(std::move(iconMap), std::move(patternMap), std::move(versionMap), pair.second); } void ImageManager::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index 9097418681..98b42da838 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -58,13 +58,7 @@ private: bool loaded = false; std::map requestors; - using Callback = std::function; - using ActorCallback = Actor; - struct MissingImageRequestPair { - ImageRequestPair pair; - std::map> callbacks; - }; - std::map missingImageRequestors; + std::map missingImageRequestors; std::map> requestedImages; std::size_t requestedImagesCacheSize = 0ul; ImageMap images; @@ -77,8 +71,18 @@ public: explicit ImageRequestor(ImageManager&); virtual ~ImageRequestor(); virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) = 0; + + void addPendingRequest(const std::string& imageId) { pendingRequests.insert(imageId); } + + bool hasPendingRequests() const { return !pendingRequests.empty(); } + + void removePendingRequest(const std::string& imageId) { pendingRequests.erase(imageId); } + private: ImageManager& imageManager; + + // Pending requests are image requests that are waiting to be dispatched to the client. + std::set pendingRequests; }; } // namespace mbgl -- cgit v1.2.1 From 71047ab8534462def95537bc15ad7b726df5c1b3 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 8 Oct 2019 22:37:53 +0300 Subject: [core] Disallow coalesced requests for patterns Unlike icons, pattern changes are not caught with style-diff meaning that the existing request could be from the previous style and we cannot coalesce requests for them. --- src/mbgl/renderer/image_manager.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index a776672edd..65defc54c8 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -170,20 +170,21 @@ void ImageManager::reduceMemoryUseIfCacheSizeExceedsLimit() { } void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageRequestPair& pair) { - std::vector missingImages; - missingImages.reserve(pair.first.size()); + ImageDependencies missingDependencies; + for (const auto& dependency : pair.first) { if (images.find(dependency.first) == images.end()) { - missingImages.push_back(dependency.first); + missingDependencies.emplace(dependency); } } - if (!missingImages.empty()) { + if (!missingDependencies.empty()) { ImageRequestor* requestorPtr = &requestor; assert(!missingImageRequestors.count(requestorPtr)); missingImageRequestors.emplace(requestorPtr, pair); - for (const auto& missingImage : missingImages) { + for (const auto& dependency : missingDependencies) { + const std::string& missingImage = dependency.first; assert(observer != nullptr); auto existingRequestorsIt = requestedImages.find(missingImage); @@ -191,8 +192,15 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR if (!existingRequestorsIt->second.empty()) { // Still waiting for the client response. existingRequestorsIt->second.emplace(requestorPtr); requestor.addPendingRequest(missingImage); + continue; + } + // Unlike icons, pattern changes are not caught + // with style-diff meaning that the existing request + // could be from the previous style and we cannot + // coalesce requests for them. + if (dependency.second != ImageType::Pattern) { + continue; } - continue; } requestedImages[missingImage].emplace(requestorPtr); requestor.addPendingRequest(missingImage); -- cgit v1.2.1 From ef8540b68373d2474449e6e5f17eaaaaab7c7f9a Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 8 Oct 2019 22:54:54 +0300 Subject: [core] Update ImageManager.OnStyleImageMissingBeforeSpriteLoaded unit test So that it checks missing images requests coalescing. --- test/renderer/image_manager.test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp index 16700d713f..f1061ce59e 100644 --- a/test/renderer/image_manager.test.cpp +++ b/test/renderer/image_manager.test.cpp @@ -187,6 +187,20 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) { EXPECT_EQ(observer.count, 1); ASSERT_TRUE(notified); + // Repeated request of the same image shall not result another + // `ImageManagerObserver.onStyleImageMissing()` call. + imageManager.getImages(requestor, std::make_pair(dependencies, imageCorrelationID)); + runLoop.runOnce(); + + EXPECT_EQ(observer.count, 1); + + // Request for updated dependencies must be dispatched to the + // observer. + dependencies.emplace("post", ImageType::Icon); + imageManager.getImages(requestor, std::make_pair(dependencies, imageCorrelationID)); + runLoop.runOnce(); + + EXPECT_EQ(observer.count, 2); } TEST(ImageManager, OnStyleImageMissingAfterSpriteLoaded) { -- cgit v1.2.1 From 76346944f3f6809bed7dd7ce4ef82343fc069423 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 9 Oct 2019 10:35:33 +0300 Subject: [ci] Fixed duplicated render tests run on MacOS --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 0046dc7fa0..d5e6eb5869 100644 --- a/circle.yml +++ b/circle.yml @@ -591,7 +591,7 @@ commands: - run: name: Run render tests (mbgl-render-test) command: | - build/mbgl-render-test render-tests render-tests --recycle-map --shuffle + build/mbgl-render-test render-tests --recycle-map --shuffle no_output_timeout: 2m run-macos-query-tests: -- cgit v1.2.1 From 2f973e9646b49f80c7af6851d38cf1029a31a232 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 10 Oct 2019 11:43:17 +0300 Subject: [core] Introduce Scheduler::bindOnce() and use it in ImageManager --- include/mbgl/actor/scheduler.hpp | 10 ++++++++++ src/mbgl/actor/scheduler.cpp | 9 ++++++++- src/mbgl/renderer/image_manager.cpp | 8 +++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/mbgl/actor/scheduler.hpp b/include/mbgl/actor/scheduler.hpp index 7338c3ab3a..bb2cf124b8 100644 --- a/include/mbgl/actor/scheduler.hpp +++ b/include/mbgl/actor/scheduler.hpp @@ -40,6 +40,16 @@ public: // Makes a weak pointer to this Scheduler. virtual mapbox::base::WeakPtr makeWeakPtr() = 0; + // Returns a closure wrapping the given one. + // + // When the returned closure is invoked for the first time, it schedules + // the given closure to this scheduler, the consequent calls of the + // returned closure are ignored. + // + // If this scheduler is already deleted by the time the returnded closure is + // first invoked, the call is ignored. + std::function bindOnce(std::function); + // Set/Get the current Scheduler for this thread static Scheduler* GetCurrent(); static void SetCurrent(Scheduler*); diff --git a/src/mbgl/actor/scheduler.cpp b/src/mbgl/actor/scheduler.cpp index 5fd9a133bd..81e259fe1f 100644 --- a/src/mbgl/actor/scheduler.cpp +++ b/src/mbgl/actor/scheduler.cpp @@ -4,7 +4,14 @@ namespace mbgl { -util::ThreadLocal g_currentScheduler; +std::function Scheduler::bindOnce(std::function fn) { + assert(fn); + return [scheduler = makeWeakPtr(), scheduled = std::move(fn)]() mutable { + if (!scheduled) return; // Repeated call. + auto schedulerGuard = scheduler.lock(); + if (scheduler) scheduler->schedule(std::move(scheduled)); + }; +} static auto& current() { static util::ThreadLocal scheduler; diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 65defc54c8..0920f5a659 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -204,6 +204,7 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR } requestedImages[missingImage].emplace(requestorPtr); requestor.addPendingRequest(missingImage); + auto removePendingRequests = [this, missingImage] { auto existingRequest = requestedImages.find(missingImage); if (existingRequest == requestedImages.end()) { @@ -214,11 +215,8 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR req->removePendingRequest(missingImage); } }; - - Scheduler& scheduler = *Scheduler::GetCurrent(); - auto callback = [&scheduler, removePendingRequests]() { scheduler.schedule(removePendingRequests); }; - - observer->onStyleImageMissing(missingImage, std::move(callback)); + observer->onStyleImageMissing(missingImage, + Scheduler::GetCurrent()->bindOnce(std::move(removePendingRequests))); } } else { // Associate requestor with an image that was provided by the client. -- cgit v1.2.1 From e909997a31621f22cf907f7c630099cd2200f135 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 10 Oct 2019 11:53:22 +0300 Subject: [android][ios] Change log entries --- platform/android/CHANGELOG.md | 1 + platform/ios/CHANGELOG.md | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index e3b07dd32e..9cc32f5632 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -13,6 +13,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Suppress network requests for expired tiles update, if these tiles are invisible. [#15741](https://github.com/mapbox/mapbox-gl-native/pull/15741) - Fixed opacity interpolation for composition expressions [#15738](https://github.com/mapbox/mapbox-gl-native/pull/15738) - Fixed an issue where `Projection#getMetersPerPixelAtLatitude` returned a value incorrectly divided by the pixel ratio. This also fixes an issue where `LocationComponent` accuracy circle's radius was artificially increased. [#15742](https://github.com/mapbox/mapbox-gl-native/pull/15742) + - Coalesce requests to the client for the same missing image [#15778](https://github.com/mapbox/mapbox-gl-native/pull/15778) ## 8.4.0 - September 25, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0-beta.1...android-v8.4.0) since [Mapbox Maps SDK for Android v8.4.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0-beta.1): diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 2f3eb809e7..b3eab70c60 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,11 +2,17 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. +## master + +### Other changes + +* Coalesce requests to the client for the same missing image ([#15778](https://github.com/mapbox/mapbox-gl-native/pull/15778)) + ## 5.5.0 ### Performance improvements - * Improved rendering performance for the styles with multiple sources ([#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756)) +* Improved rendering performance for the styles with multiple sources ([#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756)) ### Other changes -- cgit v1.2.1 From 3e06965f33d16c8135a8dc920db9f61b2f99c0db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 10 Oct 2019 12:04:38 +0200 Subject: [android] - manually write and read camera's padding array to parcel This avoids relying on Parcel's util methods that do not handle null arrays gracefully. --- .../mapbox/mapboxsdk/camera/CameraPosition.java | 23 +++++++++++++++++++--- .../mapboxsdk/camera/CameraPositionTest.java | 11 +++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) 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 e2341029ff..fb89688e28 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 @@ -30,8 +30,16 @@ public final class CameraPosition implements Parcelable { LatLng target = in.readParcelable(LatLng.class.getClassLoader()); double tilt = in.readDouble(); double zoom = in.readDouble(); - double[] padding = new double[4]; - in.readDoubleArray(padding); + + double[] padding = null; + int paddingSize = in.readInt(); + if (paddingSize > 0) { + padding = new double[paddingSize]; + for (int i = 0; i < paddingSize; i++) { + padding[i] = in.readDouble(); + } + } + return new CameraPosition(target, zoom, tilt, bearing, padding); } @@ -139,7 +147,16 @@ public final class CameraPosition implements Parcelable { out.writeParcelable(target, flags); out.writeDouble(tilt); out.writeDouble(zoom); - out.writeDoubleArray(padding); + + if (padding != null) { + int length = padding.length; + out.writeInt(length); + for (double v : padding) { + out.writeDouble(v); + } + } else { + out.writeInt(-1); + } } /** diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java index 6974705fae..dcf84c87b3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java @@ -117,4 +117,15 @@ public class CameraPositionTest { CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel); assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2); } + + @Test + public void testParcelableNulls() { + CameraPosition cameraPosition1 = new CameraPosition(null, 3, 4, 5, null); + Parcel parcel = Parcel.obtain(); + cameraPosition1.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel); + assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2); + } } -- cgit v1.2.1 From d0e6f9df448f32c38c0e5fc95a0f3f7fa7453e69 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 9 Oct 2019 14:45:21 +0300 Subject: [build] Remove redundant bots We have something equivalent on the `next` workspace for these bots. --- circle.yml | 245 ------------------------------------------------------------- 1 file changed, 245 deletions(-) diff --git a/circle.yml b/circle.yml index d5e6eb5869..d5c5b73e36 100644 --- a/circle.yml +++ b/circle.yml @@ -129,7 +129,6 @@ workflows: # unique aspect of the build environment. # - {build type} is typically "debug" or "release". # - - nitpick - android-debug-arm-v7-buck - android-arm-template: name: android-debug-arm-v8 @@ -144,25 +143,14 @@ workflows: filters: tags: only: /android-v.*/ - - node-clang39-release: - filters: - tags: - only: /node-.*/ - - node-gcc8-debug: - filters: - tags: - only: /node-.*/ - node-macos-release: filters: tags: only: /node-.*/ - - linux-clang-38-libcxx-debug: - name: linux-clang-3.8-libcxx-debug - linux-clang-7-sanitize-address-undefined - linux-clang-7-sanitize-thread - linux-gcc5-debug-coverage - linux-doxygen - - linux-render-tests - ios-debug - ios-debug-xcode10 - ios-release-template: @@ -174,7 +162,6 @@ workflows: branches: ignore: /.*/ - macos-debug - - macos-render-tests nightly: triggers: - schedule: @@ -471,16 +458,6 @@ commands: - run: name: Build node command: make node-all - build-mbgl-render-test: - steps: - - run: - name: Build mbgl-render-test - command: cmake --build build --config ${BUILDTYPE} --target mbgl-render-test -- -j${JOBS} - build-mbgl-expression-test: - steps: - - run: - name: Build mbgl-expression-test - command: cmake --build build --config ${BUILDTYPE} --target mbgl-expression-test -- -j${JOBS} build-linux: steps: - run: @@ -573,59 +550,6 @@ commands: name: Run node tests command: make test-node - run-node-linux-tests: - parameters: - node_version: - type: string - default: v8 - steps: - - run: - name: Run node tests - command: | - . "$NVM_DIR/nvm.sh" && nvm use << parameters.node_version >> - xvfb-run --server-args="-screen 0 1024x768x24" \ - logbt -- apitrace trace --api=egl -v make test-node - - run-macos-render-tests: - steps: - - run: - name: Run render tests (mbgl-render-test) - command: | - build/mbgl-render-test render-tests --recycle-map --shuffle - no_output_timeout: 2m - - run-macos-query-tests: - steps: - - run: - name: Run query tests - command: | - build/mbgl-render-test query-tests - no_output_timeout: 2m - - run-linux-render-tests: - parameters: - node_version: - type: string - default: v8 - steps: - - run: - name: Run render tests (mbgl-render-test) - command: | - xvfb-run --server-args="-screen 0 1024x768x24" \ - logbt -- apitrace trace --api=egl -v build/mbgl-render-test render-tests --recycle-map --shuffle - - run-linux-query-tests: - parameters: - node_version: - type: string - default: v8 - steps: - - run: - name: Run query tests - command: | - xvfb-run --server-args="-screen 0 1024x768x24" \ - logbt -- apitrace trace --api=egl -v build/mbgl-render-test query-tests - run-unit-tests: steps: - run: @@ -644,19 +568,6 @@ commands: # Unfortunately, Google Test eats the status code, so we'll have to check the output. [ -z "$(sed -n '/^SUMMARY: .*Sanitizer:/p' sanitizer)" ] - run-expression-tests: - steps: - - run: - name: Run expression tests - command: | - build/mbgl-expression-test -s --seed=$RANDOM - - upload-expression-tests: - steps: - - store_artifacts: - path: mapbox-gl-js/test/integration/expression-tests/index.html - destination: expression-tests - publish-node-package: steps: - run: @@ -664,18 +575,6 @@ commands: when: on_success command: platform/node/scripts/publish.sh - upload-render-tests: - steps: - - store_artifacts: - path: mapbox-gl-js/test/integration/index.html - destination: render-tests - - upload-query-tests: - steps: - - store_artifacts: - path: mapbox-gl-js/test/integration/index.html - destination: query-tests - collect-xcode-build-logs: steps: - run: @@ -815,42 +714,6 @@ jobs: test_params: << parameters.test_params >> - next-save - nitpick: - docker: - - image: mbgl/linux-clang-7:a5a3c52107 - working_directory: /src - environment: - LIBSYSCONFCPUS: 2 - JOBS: 2 - BUILDTYPE: Debug - steps: - - install-dependencies: { mason: false, ccache: false } - - run: - name: Initialize submodules - command: | - git submodule update --init - git submodule foreach git submodule update --init - - run: - name: Verify submodule pin - command: scripts/nitpick/submodule-pin.js - when: always - - run: - name: Source file list generation - command: scripts/nitpick/generated-code.js sources - when: always - - run: - name: Shader code generation - command: scripts/nitpick/generated-code.js shader - when: always - - run: - name: Style code generation - command: scripts/nitpick/generated-code.js style - when: always - - run: - name: Android code generation - command: scripts/nitpick/generated-code.js android - when: always - # ------------------------------------------------------------------------------ android-arm-template: parameters: @@ -1071,42 +934,6 @@ jobs: cd misc/buck buck build mapbox-gl-native:android-core -# ------------------------------------------------------------------------------ - node-clang39-release: - docker: - - image: mbgl/linux-clang-3.9:2077f965ed - resource_class: large - working_directory: /src - environment: - LIBSYSCONFCPUS: 4 - JOBS: 4 - BUILDTYPE: RelWithDebInfo - WITH_EGL: 1 - steps: - - install-dependencies - - build-node - - save-dependencies - - run-node-linux-tests - - publish-node-package - -# ------------------------------------------------------------------------------ - node-gcc8-debug: - docker: - - image: mbgl/linux-gcc-8:d2b1553d2f - resource_class: large - working_directory: /src - environment: - LIBSYSCONFCPUS: 4 - JOBS: 4 - BUILDTYPE: Debug - WITH_EGL: 1 - steps: - - install-dependencies - - check-if-this-job-can-be-skipped - - build-node - - save-dependencies - - publish-node-package - # ------------------------------------------------------------------------------ node-macos-release: macos: @@ -1127,23 +954,6 @@ jobs: - collect-xcode-build-logs - upload-xcode-build-logs -# ------------------------------------------------------------------------------ - linux-clang-38-libcxx-debug: - docker: - - image: mbgl/linux-clang-3.8-libcxx:d6800bdbb4 - resource_class: large - working_directory: /src - environment: - LIBSYSCONFCPUS: 4 - JOBS: 4 - BUILDTYPE: Debug - WITH_EGL: 1 - steps: - - install-dependencies - - check-if-this-job-can-be-skipped - - build-linux - - save-dependencies - # ------------------------------------------------------------------------------ linux-clang-7-sanitize-address-undefined: docker: @@ -1248,31 +1058,6 @@ jobs: platform/linux/ninja -C "build/linux-$(uname -m)/Debug" doxygen_coverage scripts/publish_doxygen_coverage.js "build/linux-$(uname -m)/Debug/doxygen-coverage.json" -# ------------------------------------------------------------------------------ - linux-render-tests: - docker: - - image: mbgl/linux-clang-7:a5a3c52107 - resource_class: large - working_directory: /src - environment: - LIBSYSCONFCPUS: 4 - JOBS: 4 - BUILDTYPE: RelWithDebInfo - WITH_EGL: 1 - steps: - - install-dependencies - - check-if-this-job-can-be-skipped - - configure-cmake - - build-mbgl-expression-test - - build-mbgl-render-test - - run-expression-tests - - upload-expression-tests - - run-linux-render-tests - - upload-render-tests - - run-linux-query-tests - - upload-query-tests - - save-dependencies - # ------------------------------------------------------------------------------ ios-debug: macos: @@ -1293,9 +1078,6 @@ jobs: - run: name: Check symbol namespacing for mapbox-events-ios command: make ios-check-events-symbols - - run: - name: Nitpick Darwin code generation - command: scripts/nitpick/generated-code.js darwin - save-dependencies - collect-xcode-build-logs - upload-xcode-build-logs @@ -1320,9 +1102,6 @@ jobs: - run: name: Check symbol namespacing for mapbox-events-ios command: make ios-check-events-symbols - - run: - name: Nitpick Darwin code generation - command: scripts/nitpick/generated-code.js darwin - save-dependencies - collect-xcode-build-logs - upload-xcode-build-logs @@ -1547,30 +1326,6 @@ jobs: - collect-xcode-build-logs - upload-xcode-build-logs -# ------------------------------------------------------------------------------ - macos-render-tests: - macos: - xcode: "11.0.0" - environment: - BUILDTYPE: RelWithDebInfo - HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - JOBS: 2 - steps: - - install-macos-dependencies - - install-dependencies - - check-if-this-job-can-be-skipped - - configure-cmake - - build-mbgl-expression-test - - build-mbgl-render-test - - save-dependencies - - run-expression-tests - - upload-expression-tests - - run-macos-render-tests - - upload-render-tests - - run-macos-query-tests - - upload-query-tests - # ------------------------------------------------------------------------------ metrics-nightly: docker: -- cgit v1.2.1 From 5f371d5e39e1b76435501245f2837cc9079c7bbc Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 9 Oct 2019 15:08:14 +0300 Subject: [build] Check for code generation on Darwin Sadly, it can only be done inside macOS because of how examples are generated. --- circle.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/circle.yml b/circle.yml index d5c5b73e36..e53444dc7f 100644 --- a/circle.yml +++ b/circle.yml @@ -221,6 +221,12 @@ commands: name: Prepare macOS command: | brew install cmake ccache glfw ninja pkgconfig qt + - run: + name: Code Generators macOS + command: | + platform/darwin/scripts/generate-style-code.js + platform/darwin/scripts/update-examples.js + git add -A && git diff --staged --exit-code next-config: parameters: config_params: -- cgit v1.2.1 From 2a3cc96c4208a0d352dfee41ed1f29a756abe44c Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Thu, 10 Oct 2019 18:44:52 +0300 Subject: [tests] Do not run tests in parallel Introduces too much flakeness. --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index e53444dc7f..a26bdb39c1 100644 --- a/circle.yml +++ b/circle.yml @@ -280,7 +280,7 @@ commands: name: Test command: | cd build - << parameters.test_wrapper >> ctest -j 8 --output-on-failure << parameters.test_params >> + << parameters.test_wrapper >> ctest --output-on-failure << parameters.test_params >> npm-install: steps: - run: -- cgit v1.2.1 From 026e15fe3d6dae0c3f11775d19dcfc13743ff1c0 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 9 Oct 2019 19:11:31 +0300 Subject: [render-test] Fix rootPath parameter being ignored It was doing nothing and always using the default root path. --- render-test/parser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 024adf91d1..e9df704941 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -365,11 +365,11 @@ ArgumentsTuple parseArguments(int argc, char** argv) { std::vector paths; for (const auto& id : args::get(testNameValues)) { - paths.emplace_back(TestRunner::getBasePath() + "/" + id); + paths.emplace_back(rootPath / id); } if (paths.empty()) { - paths.emplace_back(TestRunner::getBasePath()); + paths.emplace_back(rootPath); } // Recursively traverse through the test paths and collect test directories containing "style.json". -- cgit v1.2.1 From a9f06f3b527601fc0d7a1c254af414e7a313eef0 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 9 Oct 2019 16:12:02 +0300 Subject: [render-test] Add instruction for verifying file size For a given absolute or relative path, measure the size of the file. This is useful for measuring if the cache has increased as expected after moving a camera or decreased after cleaning up. In a more hackish manner, could be used for collecting binary size statistics of shared libraries. --- render-test/metadata.hpp | 11 ++++++++++- render-test/parser.cpp | 39 ++++++++++++++++++++++++++++++++++++++ render-test/runner.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index d25b81c7ab..e881bce208 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -31,6 +31,14 @@ struct TestPaths { } }; +struct FileSizeProbe { + FileSizeProbe() = default; + FileSizeProbe(std::string path_, uintmax_t size_) : path(std::move(path_)), size(size_) {} + + std::string path; + uintmax_t size; +}; + struct MemoryProbe { MemoryProbe() = default; MemoryProbe(size_t peak_, size_t allocations_) @@ -43,7 +51,8 @@ struct MemoryProbe { class TestMetrics { public: - bool isEmpty() const { return memory.empty(); } + bool isEmpty() const { return fileSize.empty() && memory.empty(); } + std::map fileSize; std::map memory; }; diff --git a/render-test/parser.cpp b/render-test/parser.cpp index e9df704941..613fc566ea 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -273,6 +273,21 @@ std::string serializeMetrics(const TestMetrics& metrics) { rapidjson::Writer writer(s); writer.StartObject(); + + // Start fileSize section. + writer.Key("fileSize"); + writer.StartArray(); + for (const auto& fileSizeProbe : metrics.fileSize) { + assert(!fileSizeProbe.first.empty()); + writer.StartArray(); + writer.String(fileSizeProbe.first.c_str()); + writer.String(fileSizeProbe.second.path); + writer.Uint64(fileSizeProbe.second.size); + writer.EndArray(); + } + // End fileSize section. + writer.EndArray(); + // Start memory section. writer.Key("memory"); writer.StartArray(); @@ -286,6 +301,7 @@ std::string serializeMetrics(const TestMetrics& metrics) { } // End memory section. writer.EndArray(); + writer.EndObject(); return s.GetString(); @@ -439,6 +455,29 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { } const auto& document = maybeJson.get(); + + if (document.HasMember("fileSize")) { + const mbgl::JSValue& fileSizeValue = document["fileSize"]; + assert(fileSizeValue.IsArray()); + for (auto& probeValue : fileSizeValue.GetArray()) { + assert(probeValue.IsArray()); + assert(probeValue.Size() >= 3u); + assert(probeValue[0].IsString()); + assert(probeValue[1].IsString()); + assert(probeValue[2].IsNumber()); + + std::string mark{probeValue[0].GetString(), probeValue[0].GetStringLength()}; + assert(!mark.empty()); + + std::string filePath{probeValue[1].GetString(), probeValue[1].GetStringLength()}; + assert(!filePath.empty()); + + result.fileSize.emplace(std::piecewise_construct, + std::forward_as_tuple(std::move(mark)), + std::forward_as_tuple(std::move(filePath), probeValue[2].GetUint64())); + } + } + if (document.HasMember("memory")) { const mbgl::JSValue& memoryValue = document["memory"]; assert(memoryValue.IsArray()); diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 5df167431f..6b726a8eeb 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -242,6 +242,31 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, break; } } + // Check file size metrics. + for (const auto& expected : metadata.expectedMetrics.fileSize) { + auto actual = metadata.metrics.fileSize.find(expected.first); + if (actual == metadata.metrics.fileSize.end()) { + metadata.errorMessage = "Failed to find fileSize probe: " + expected.first; + return false; + } + if (actual->second.path != expected.second.path) { + std::stringstream ss; + ss << "Comparing different files at probe \"" << expected.first << "\": " << actual->second.path + << ", expected is " << expected.second.path << "."; + metadata.errorMessage = ss.str(); + + return false; + } + + if (actual->second.size != expected.second.size) { + std::stringstream ss; + ss << "File size does not match at probe \"" << expected.first << "\": " << actual->second.size + << ", expected is " << expected.second.size << "."; + + metadata.errorMessage = ss.str(); + return false; + } + } // Check memory metrics. for (const auto& expected : metadata.expectedMetrics.memory) { auto actual = metadata.metrics.memory.find(expected.first); @@ -313,6 +338,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { static const std::string removeSourceOp("removeSource"); static const std::string setPaintPropertyOp("setPaintProperty"); static const std::string setLayoutPropertyOp("setLayoutProperty"); + static const std::string fileSizeProbeOp("probeFileSize"); static const std::string memoryProbeOp("probeMemory"); static const std::string memoryProbeStartOp("probeMemoryStart"); static const std::string memoryProbeEndOp("probeMemoryEnd"); @@ -562,6 +588,29 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { const mbgl::JSValue* propertyValue = &operationArray[3]; layer->setLayoutProperty(propertyName, propertyValue); } + // probeFileSize + } else if (operationArray[0].GetString() == fileSizeProbeOp) { + assert(operationArray.Size() >= 3u); + assert(operationArray[1].IsString()); + assert(operationArray[2].IsString()); + + std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength()); + mbgl::filesystem::path path = std::string(operationArray[2].GetString(), operationArray[2].GetStringLength()); + assert(!path.empty()); + + if (!path.is_absolute()) { + path = metadata.paths.defaultExpectations() / path; + } + + if (mbgl::filesystem::exists(path)) { + auto size = mbgl::filesystem::file_size(path); + metadata.metrics.fileSize.emplace(std::piecewise_construct, + std::forward_as_tuple(std::move(mark)), + std::forward_as_tuple(std::move(path), size)); + } else { + metadata.errorMessage = std::string("File not found: ") + path.string(); + return false; + } // probeMemoryStart } else if (operationArray[0].GetString() == memoryProbeStartOp) { assert(!AllocationIndex::isActive()); -- cgit v1.2.1 From 2e002746eb6fcbf389fd4c59fa55bd8ee527076f Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 9 Oct 2019 16:30:06 +0300 Subject: [render-test] Make clang-format happy --- render-test/runner.cpp | 69 ++++++++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 44 deletions(-) diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 6b726a8eeb..f056902b7f 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -346,15 +346,15 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { static const std::string getFeatureStateOp("getFeatureState"); static const std::string removeFeatureStateOp("removeFeatureState"); - // wait if (operationArray[0].GetString() == waitOp) { + // wait try { frontend.render(map); } catch (const std::exception&) { return false; } - // sleep } else if (operationArray[0].GetString() == sleepOp) { + // sleep mbgl::util::Timer sleepTimer; bool sleeping = true; @@ -370,9 +370,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { while (sleeping) { mbgl::util::RunLoop::Get()->runOnce(); } - - // addImage | updateImage } else if (operationArray[0].GetString() == addImageOp || operationArray[0].GetString() == updateImageOp) { + // addImage | updateImage assert(operationArray.Size() >= 3u); float pixelRatio = 1.0f; @@ -404,17 +403,15 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } map.getStyle().addImage(std::make_unique(imageName, mbgl::decodeImage(*maybeImage), pixelRatio, sdf)); - - // removeImage } else if (operationArray[0].GetString() == removeImageOp) { + // removeImage assert(operationArray.Size() >= 2u); assert(operationArray[1].IsString()); const std::string imageName { operationArray[1].GetString(), operationArray[1].GetStringLength() }; map.getStyle().removeImage(imageName); - - // setStyle } else if (operationArray[0].GetString() == setStyleOp) { + // setStyle assert(operationArray.Size() >= 2u); if (operationArray[1].IsString()) { std::string stylePath = localizeURL(operationArray[1].GetString()); @@ -428,9 +425,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { localizeStyleURLs(operationArray[1], metadata.document); map.getStyle().loadJSON(serializeJsonValue(operationArray[1])); } - - // setCenter } else if (operationArray[0].GetString() == setCenterOp) { + // setCenter assert(operationArray.Size() >= 2u); assert(operationArray[1].IsArray()); @@ -438,27 +434,23 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(centerArray.Size() == 2u); map.jumpTo(mbgl::CameraOptions().withCenter(mbgl::LatLng(centerArray[1].GetDouble(), centerArray[0].GetDouble()))); - - // setZoom } else if (operationArray[0].GetString() == setZoomOp) { + // setZoom assert(operationArray.Size() >= 2u); assert(operationArray[1].IsNumber()); map.jumpTo(mbgl::CameraOptions().withZoom(operationArray[1].GetDouble())); - - // setBearing } else if (operationArray[0].GetString() == setBearingOp) { + // setBearing assert(operationArray.Size() >= 2u); assert(operationArray[1].IsNumber()); map.jumpTo(mbgl::CameraOptions().withBearing(operationArray[1].GetDouble())); - - // setPitch } else if (operationArray[0].GetString() == setPitchOp) { + // setPitch assert(operationArray.Size() >= 2u); assert(operationArray[1].IsNumber()); map.jumpTo(mbgl::CameraOptions().withPitch(operationArray[1].GetDouble())); - - // setFilter } else if (operationArray[0].GetString() == setFilterOp) { + // setFilter assert(operationArray.Size() >= 3u); assert(operationArray[1].IsString()); @@ -478,9 +470,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { layer->setFilter(std::move(*converted)); } } - - // setLayerZoomRange } else if (operationArray[0].GetString() == setLayerZoomRangeOp) { + // setLayerZoomRange assert(operationArray.Size() >= 4u); assert(operationArray[1].IsString()); assert(operationArray[2].IsNumber()); @@ -495,9 +486,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { layer->setMinZoom(operationArray[2].GetFloat()); layer->setMaxZoom(operationArray[3].GetFloat()); } - - // setLight } else if (operationArray[0].GetString() == setLightOp) { + // setLight assert(operationArray.Size() >= 2u); assert(operationArray[1].IsObject()); @@ -509,9 +499,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } else { map.getStyle().setLight(std::make_unique(std::move(*converted))); } - - // addLayer } else if (operationArray[0].GetString() == addLayerOp) { + // addLayer assert(operationArray.Size() >= 2u); assert(operationArray[1].IsObject()); @@ -523,15 +512,13 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } else { map.getStyle().addLayer(std::move(*converted)); } - - // removeLayer } else if (operationArray[0].GetString() == removeLayerOp) { + // removeLayer assert(operationArray.Size() >= 2u); assert(operationArray[1].IsString()); map.getStyle().removeLayer(operationArray[1].GetString()); - - // addSource } else if (operationArray[0].GetString() == addSourceOp) { + // addSource assert(operationArray.Size() >= 3u); assert(operationArray[1].IsString()); assert(operationArray[2].IsObject()); @@ -546,15 +533,13 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } else { map.getStyle().addSource(std::move(*converted)); } - - // removeSource } else if (operationArray[0].GetString() == removeSourceOp) { + // removeSource assert(operationArray.Size() >= 2u); assert(operationArray[1].IsString()); map.getStyle().removeSource(operationArray[1].GetString()); - - // setPaintProperty } else if (operationArray[0].GetString() == setPaintPropertyOp) { + // setPaintProperty assert(operationArray.Size() >= 4u); assert(operationArray[1].IsString()); assert(operationArray[2].IsString()); @@ -570,9 +555,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { const mbgl::JSValue* propertyValue = &operationArray[3]; layer->setPaintProperty(propertyName, propertyValue); } - - // setLayoutProperty } else if (operationArray[0].GetString() == setLayoutPropertyOp) { + // setLayoutProperty assert(operationArray.Size() >= 4u); assert(operationArray[1].IsString()); assert(operationArray[2].IsString()); @@ -588,8 +572,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { const mbgl::JSValue* propertyValue = &operationArray[3]; layer->setLayoutProperty(propertyName, propertyValue); } - // probeFileSize } else if (operationArray[0].GetString() == fileSizeProbeOp) { + // probeFileSize assert(operationArray.Size() >= 3u); assert(operationArray[1].IsString()); assert(operationArray[2].IsString()); @@ -611,12 +595,12 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { metadata.errorMessage = std::string("File not found: ") + path.string(); return false; } - // probeMemoryStart } else if (operationArray[0].GetString() == memoryProbeStartOp) { + // probeMemoryStart assert(!AllocationIndex::isActive()); AllocationIndex::setActive(true); - // probeMemory } else if (operationArray[0].GetString() == memoryProbeOp) { + // probeMemory assert(AllocationIndex::isActive()); assert(operationArray.Size() >= 2u); assert(operationArray[1].IsString()); @@ -625,14 +609,13 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { metadata.metrics.memory.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(mark)), std::forward_as_tuple(AllocationIndex::getAllocatedSizePeak(), AllocationIndex::getAllocationsCount())); - // probeMemoryEnd } else if (operationArray[0].GetString() == memoryProbeEndOp) { + // probeMemoryEnd assert(AllocationIndex::isActive()); AllocationIndex::setActive(false); AllocationIndex::reset(); - - // setFeatureState } else if (operationArray[0].GetString() == setFeatureStateOp) { + // setFeatureState assert(operationArray.Size() >= 3u); assert(operationArray[1].IsObject()); assert(operationArray[2].IsObject()); @@ -707,9 +690,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { return false; } frontend.getRenderer()->setFeatureState(sourceID, sourceLayer, featureID, parsedState); - - // getFeatureState } else if (operationArray[0].GetString() == getFeatureStateOp) { + // getFeatureState assert(operationArray.Size() >= 2u); assert(operationArray[1].IsObject()); @@ -739,9 +721,8 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } mbgl::FeatureState state; frontend.getRenderer()->getFeatureState(state, sourceID, sourceLayer, featureID); - - // removeFeatureState } else if (operationArray[0].GetString() == removeFeatureStateOp) { + // removeFeatureState assert(operationArray.Size() >= 2u); assert(operationArray[1].IsObject()); -- cgit v1.2.1 From 629c0e1142a382ada101e93e7c58bd2b1bce37bc Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 9 Oct 2019 22:00:30 +0300 Subject: [render-test] Add tests for filesize probe And make sure we run it on the bots --- .gitignore | 5 +-- next/render-test/CMakeLists.txt | 15 +++++++-- render-test/parser.cpp | 8 +++-- .../filesize/fail-file-doesnt-match/expected.png | Bin 0 -> 686 bytes .../filesize/fail-file-doesnt-match/style.json | 36 +++++++++++++++++++++ .../tests/filesize/fail-size-is-over/expected.png | Bin 0 -> 686 bytes .../tests/filesize/fail-size-is-over/metrics.json | 1 + .../tests/filesize/fail-size-is-over/style.json | 36 +++++++++++++++++++++ .../tests/filesize/fail-size-is-under/expected.png | Bin 0 -> 686 bytes .../tests/filesize/fail-size-is-under/metrics.json | 1 + .../tests/filesize/fail-size-is-under/style.json | 36 +++++++++++++++++++++ .../tests/filesize/pass-size-is-same/expected.png | Bin 0 -> 686 bytes .../tests/filesize/pass-size-is-same/metrics.json | 1 + .../tests/filesize/pass-size-is-same/style.json | 36 +++++++++++++++++++++ render-test/tests/should-fail.json | 5 +++ 15 files changed, 173 insertions(+), 7 deletions(-) create mode 100644 render-test/tests/filesize/fail-file-doesnt-match/expected.png create mode 100644 render-test/tests/filesize/fail-file-doesnt-match/style.json create mode 100644 render-test/tests/filesize/fail-size-is-over/expected.png create mode 100644 render-test/tests/filesize/fail-size-is-over/metrics.json create mode 100644 render-test/tests/filesize/fail-size-is-over/style.json create mode 100644 render-test/tests/filesize/fail-size-is-under/expected.png create mode 100644 render-test/tests/filesize/fail-size-is-under/metrics.json create mode 100644 render-test/tests/filesize/fail-size-is-under/style.json create mode 100644 render-test/tests/filesize/pass-size-is-same/expected.png create mode 100644 render-test/tests/filesize/pass-size-is-same/metrics.json create mode 100644 render-test/tests/filesize/pass-size-is-same/style.json create mode 100644 render-test/tests/should-fail.json diff --git a/.gitignore b/.gitignore index bf6b13e007..538870edf7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ *.gcno *.gcda *~ +**/actual.png +**/diff.png +render-test/index.html offline.db new_offline.db xcuserdata @@ -19,8 +22,6 @@ xcuserdata /test/fixtures/api/2.png /test/fixtures/offline_database/offline.db /test/fixtures/offline_database/offline.db-* -/test/fixtures/**/actual.png -/test/fixtures/**/diff.png /test/output /node_modules /platform/ios/benchmark/assets/glyphs/DIN* diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 5aadd0f859..80709d2b89 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -47,8 +47,19 @@ add_test( render-tests --recycle-map --shuffle - --seed - ${MBGL_RENDER_TEST_SEED} + --seed=${MBGL_RENDER_TEST_SEED} + WORKING_DIRECTORY ${MBGL_ROOT} +) + +add_test( + NAME mbgl-render-test-probes + COMMAND + mbgl-render-test + render-tests + --recycle-map + --shuffle + --seed=${MBGL_RENDER_TEST_SEED} + --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT} ) diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 613fc566ea..3da7e6ea01 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -421,15 +421,17 @@ std::vector> parseIgnores() { auto mainIgnoresPath = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("platform/node/test/ignores.json"); mbgl::filesystem::path platformSpecificIgnores; + mbgl::filesystem::path ownTestsIgnores = + mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("render-test/tests/should-fail.json"); #ifdef __APPLE__ platformSpecificIgnores = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("render-test/mac-ignores.json"); #elif __linux__ platformSpecificIgnores = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("render-test/linux-ignores.json"); #endif - - std::vector ignoresPaths = { mainIgnoresPath, platformSpecificIgnores }; - for (auto path: ignoresPaths) { + + std::vector ignoresPaths = {mainIgnoresPath, platformSpecificIgnores, ownTestsIgnores}; + for (const auto& path : ignoresPaths) { auto maybeIgnores = readJson(path); if (!maybeIgnores.is()) { continue; diff --git a/render-test/tests/filesize/fail-file-doesnt-match/expected.png b/render-test/tests/filesize/fail-file-doesnt-match/expected.png new file mode 100644 index 0000000000..feed2e457f Binary files /dev/null and b/render-test/tests/filesize/fail-file-doesnt-match/expected.png differ diff --git a/render-test/tests/filesize/fail-file-doesnt-match/style.json b/render-test/tests/filesize/fail-file-doesnt-match/style.json new file mode 100644 index 0000000000..91e90ffbe8 --- /dev/null +++ b/render-test/tests/filesize/fail-file-doesnt-match/style.json @@ -0,0 +1,36 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "aaaaa.json"], + ["probeFileSize", "image", "bbbbb.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "symbol", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": "circle-12" + } + } + ] +} diff --git a/render-test/tests/filesize/fail-size-is-over/expected.png b/render-test/tests/filesize/fail-size-is-over/expected.png new file mode 100644 index 0000000000..feed2e457f Binary files /dev/null and b/render-test/tests/filesize/fail-size-is-over/expected.png differ diff --git a/render-test/tests/filesize/fail-size-is-over/metrics.json b/render-test/tests/filesize/fail-size-is-over/metrics.json new file mode 100644 index 0000000000..2df7e7da11 --- /dev/null +++ b/render-test/tests/filesize/fail-size-is-over/metrics.json @@ -0,0 +1 @@ +{"fileSize":[["image","../render-test/tests/filesize/fail-size-is-over/expected.png",100],["style","../render-test/tests/filesize/fail-size-is-over/style.json",100]]} diff --git a/render-test/tests/filesize/fail-size-is-over/style.json b/render-test/tests/filesize/fail-size-is-over/style.json new file mode 100644 index 0000000000..ce2069a372 --- /dev/null +++ b/render-test/tests/filesize/fail-size-is-over/style.json @@ -0,0 +1,36 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "symbol", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": "circle-12" + } + } + ] +} diff --git a/render-test/tests/filesize/fail-size-is-under/expected.png b/render-test/tests/filesize/fail-size-is-under/expected.png new file mode 100644 index 0000000000..feed2e457f Binary files /dev/null and b/render-test/tests/filesize/fail-size-is-under/expected.png differ diff --git a/render-test/tests/filesize/fail-size-is-under/metrics.json b/render-test/tests/filesize/fail-size-is-under/metrics.json new file mode 100644 index 0000000000..92d3f1e3d5 --- /dev/null +++ b/render-test/tests/filesize/fail-size-is-under/metrics.json @@ -0,0 +1 @@ +{"fileSize":[["image","../render-test/tests/filesize/fail-size-is-under/expected.png",999],["style","../render-test/tests/filesize/fail-size-is-under/style.json",999]]} diff --git a/render-test/tests/filesize/fail-size-is-under/style.json b/render-test/tests/filesize/fail-size-is-under/style.json new file mode 100644 index 0000000000..ce2069a372 --- /dev/null +++ b/render-test/tests/filesize/fail-size-is-under/style.json @@ -0,0 +1,36 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "symbol", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": "circle-12" + } + } + ] +} diff --git a/render-test/tests/filesize/pass-size-is-same/expected.png b/render-test/tests/filesize/pass-size-is-same/expected.png new file mode 100644 index 0000000000..feed2e457f Binary files /dev/null and b/render-test/tests/filesize/pass-size-is-same/expected.png differ diff --git a/render-test/tests/filesize/pass-size-is-same/metrics.json b/render-test/tests/filesize/pass-size-is-same/metrics.json new file mode 100644 index 0000000000..4c01d3b2ca --- /dev/null +++ b/render-test/tests/filesize/pass-size-is-same/metrics.json @@ -0,0 +1 @@ +{"fileSize":[["image","../render-test/tests/filesize/pass-size-is-same/expected.png",686],["style","../render-test/tests/filesize/pass-size-is-same/style.json",609]]} \ No newline at end of file diff --git a/render-test/tests/filesize/pass-size-is-same/style.json b/render-test/tests/filesize/pass-size-is-same/style.json new file mode 100644 index 0000000000..ce2069a372 --- /dev/null +++ b/render-test/tests/filesize/pass-size-is-same/style.json @@ -0,0 +1,36 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "sprite": "local://sprites/sprite", + "layers": [ + { + "id": "symbol", + "type": "symbol", + "source": "geojson", + "layout": { + "icon-image": "circle-12" + } + } + ] +} diff --git a/render-test/tests/should-fail.json b/render-test/tests/should-fail.json new file mode 100644 index 0000000000..28859d4151 --- /dev/null +++ b/render-test/tests/should-fail.json @@ -0,0 +1,5 @@ +{ + "tests/filesize/fail-size-is-over": "Should fail, size is bigger than expected.", + "tests/filesize/fail-size-is-under": "Should fail, size is smaller than expected.", + "tests/filesize/fail-file-doesnt-match": "Should fail, file not found." +} -- cgit v1.2.1 From 63116154fe7e1f49d7751c002e2abe5422fd22ee Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Thu, 10 Oct 2019 18:48:17 +0300 Subject: [render-test] Only write metrics if they are available Otherwise the file will have an empty tag. --- render-test/parser.cpp | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 3da7e6ea01..34cccad2a2 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -275,32 +275,34 @@ std::string serializeMetrics(const TestMetrics& metrics) { writer.StartObject(); // Start fileSize section. - writer.Key("fileSize"); - writer.StartArray(); - for (const auto& fileSizeProbe : metrics.fileSize) { - assert(!fileSizeProbe.first.empty()); + if (!metrics.fileSize.empty()) { + writer.Key("fileSize"); writer.StartArray(); - writer.String(fileSizeProbe.first.c_str()); - writer.String(fileSizeProbe.second.path); - writer.Uint64(fileSizeProbe.second.size); + for (const auto& fileSizeProbe : metrics.fileSize) { + assert(!fileSizeProbe.first.empty()); + writer.StartArray(); + writer.String(fileSizeProbe.first.c_str()); + writer.String(fileSizeProbe.second.path); + writer.Uint64(fileSizeProbe.second.size); + writer.EndArray(); + } writer.EndArray(); } - // End fileSize section. - writer.EndArray(); // Start memory section. - writer.Key("memory"); - writer.StartArray(); - for (const auto& memoryProbe : metrics.memory) { - assert(!memoryProbe.first.empty()); + if (!metrics.memory.empty()) { + writer.Key("memory"); writer.StartArray(); - writer.String(memoryProbe.first.c_str()); - writer.Uint64(memoryProbe.second.peak); - writer.Uint64(memoryProbe.second.allocations); + for (const auto& memoryProbe : metrics.memory) { + assert(!memoryProbe.first.empty()); + writer.StartArray(); + writer.String(memoryProbe.first.c_str()); + writer.Uint64(memoryProbe.second.peak); + writer.Uint64(memoryProbe.second.allocations); + writer.EndArray(); + } writer.EndArray(); } - // End memory section. - writer.EndArray(); writer.EndObject(); -- cgit v1.2.1 From 1dc01f66441272402d35f0c4d52764d69a900493 Mon Sep 17 00:00:00 2001 From: tobrun Date: Thu, 10 Oct 2019 18:13:20 +0200 Subject: [android] update changelog for 8.5.0-alpha.2 --- platform/android/CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 9cc32f5632..8fb977140c 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,11 +2,19 @@ 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. -## master +## 8.5.0-alpha.2 - October 10, 2019 +[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.5.0-alpha.1...android-v8.5.0-alpha.2) since [Mapbox Maps SDK for Android v8.5.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.5.0-alpha.1): + +### Features + - Expose pre-fetching zoom delta, allows to granular control the delta on which we prefetch tiles [#15769](https://github.com/mapbox/mapbox-gl-native/pull/15769) ### Performance improvements - Improved rendering performance for the styles with multiple sources [#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756) +### Bug fixes + - Fixed runtime exceptions that occurred when a manually built camera object without padding was serialized. [#15788](https://github.com/mapbox/mapbox-gl-native/pull/15788) + - Keep Mapbox when obfuscating code with proguard [#15762](https://github.com/mapbox/mapbox-gl-native/pull/15762) + ## 8.5.0-alpha.1 - October 3, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.4.0...android-v8.5.0-alpha.1) since [Mapbox Maps SDK for Android v8.4.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.4.0): ### Bug fixes -- cgit v1.2.1 From bf61274b2a64bfa5d3b13ba988a97e9d32934713 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Thu, 10 Oct 2019 16:27:02 -0400 Subject: [ios, android] Update curl command to indicate there is no password (as per https://circleci.com/docs/api/#authentication) (#15796) --- circle.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/circle.yml b/circle.yml index a26bdb39c1..b358e38d5f 100644 --- a/circle.yml +++ b/circle.yml @@ -839,7 +839,7 @@ jobs: command: | if [ -n "${MOBILE_METRICS_TOKEN}" ]; then if [[ $CIRCLE_BRANCH == master ]]; then - curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=android-core-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master + curl -u ${MOBILE_METRICS_TOKEN}: -d build_parameters[CIRCLE_JOB]=android-core-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master fi fi - run: @@ -847,7 +847,7 @@ jobs: command: | if [ -n "${MOBILE_METRICS_TOKEN}" ]; then if [[ $CIRCLE_BRANCH == master ]]; then - curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=android-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master + curl -u ${MOBILE_METRICS_TOKEN}: -d build_parameters[CIRCLE_JOB]=android-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master fi fi - run: @@ -1241,7 +1241,7 @@ jobs: command: | if [[ $CIRCLE_BRANCH == master ]]; then if [ -n "${MOBILE_METRICS_TOKEN}" ]; then - curl -u $MOBILE_METRICS_TOKEN -d build_parameters[CIRCLE_JOB]=ios-maps-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master + curl -u ${MOBILE_METRICS_TOKEN}: -d build_parameters[CIRCLE_JOB]=ios-maps-benchmark https://circleci.com/api/v1.1/project/github/mapbox/mobile-metrics/tree/master else echo "MOBILE_METRICS_TOKEN not provided" fi -- cgit v1.2.1 From bebc49949a551150de8e557bf15563283516a59b Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Thu, 10 Oct 2019 21:04:40 +0300 Subject: [render-test] Update location of render / query test html page --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index b358e38d5f..083ea121a0 100644 --- a/circle.yml +++ b/circle.yml @@ -263,7 +263,7 @@ commands: when: on_fail command: | mkdir -p /tmp/tests/render - if [ -f mapbox-gl-js/test/integration/render-tests/index.html ]; then cp mapbox-gl-js/test/integration/render-tests/index.html /tmp/tests/render; fi + if [ -f mapbox-gl-js/test/integration/index.html ]; then cp mapbox-gl-js/test/integration/index.html /tmp/tests/render; fi mkdir -p /tmp/tests/coredumps if ls core* 1> /dev/null 2>&1; then cp core* /tmp/tests/coredumps; fi - store_artifacts: -- cgit v1.2.1 From 990fdc43facab2d296f35bc8670a926d05fbe864 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Thu, 10 Oct 2019 19:33:15 +0300 Subject: [build] Make sure offline_schema.hpp is up-to-date - Get the bots to verify that. - Fix the paths. --- circle.yml | 1 + platform/default/include/mbgl/storage/offline_schema.hpp | 2 +- platform/default/include/mbgl/storage/offline_schema.js | 8 +++++--- 3 files changed, 7 insertions(+), 4 deletions(-) mode change 100644 => 100755 platform/default/include/mbgl/storage/offline_schema.js diff --git a/circle.yml b/circle.yml index 083ea121a0..d549cbe563 100644 --- a/circle.yml +++ b/circle.yml @@ -642,6 +642,7 @@ jobs: name: Code Generators command: | platform/android/scripts/generate-style-code.js + platform/default/include/mbgl/storage/offline_schema.js scripts/generate-file-lists.js scripts/generate-shaders.js scripts/generate-style-code.js diff --git a/platform/default/include/mbgl/storage/offline_schema.hpp b/platform/default/include/mbgl/storage/offline_schema.hpp index e177d0dbd3..77c66b7d15 100644 --- a/platform/default/include/mbgl/storage/offline_schema.hpp +++ b/platform/default/include/mbgl/storage/offline_schema.hpp @@ -1,7 +1,7 @@ #pragma once // THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD -// To regenerate, run `node platform/default/mbgl/storage/offline_schema.js` +// To regenerate, run `node platform/default/include/mbgl/storage/offline_schema.js` namespace mbgl { diff --git a/platform/default/include/mbgl/storage/offline_schema.js b/platform/default/include/mbgl/storage/offline_schema.js old mode 100644 new mode 100755 index fdb7dc6405..a58e216d4a --- a/platform/default/include/mbgl/storage/offline_schema.js +++ b/platform/default/include/mbgl/storage/offline_schema.js @@ -1,13 +1,15 @@ +#!/usr/bin/env node + var fs = require('fs'); -fs.writeFileSync('platform/default/mbgl/storage/offline_schema.hpp', `#pragma once +fs.writeFileSync('platform/default/include/mbgl/storage/offline_schema.hpp', `#pragma once // THIS IS A GENERATED FILE; EDIT offline_schema.sql INSTEAD -// To regenerate, run \`node platform/default/mbgl/storage/offline_schema.js\` +// To regenerate, run \`node platform/default/include/mbgl/storage/offline_schema.js\` namespace mbgl { static constexpr const char* offlineDatabaseSchema = -${fs.readFileSync('platform/default/mbgl/storage/offline_schema.sql', 'utf8') +${fs.readFileSync('platform/default/include/mbgl/storage/offline_schema.sql', 'utf8') .replace(/ *--.*/g, '') .split('\n') .filter(a => a) -- cgit v1.2.1 From a4e1707f6b0b6610284e30b5068050f90ede9ae4 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Thu, 10 Oct 2019 20:53:58 +0300 Subject: [offline] Document the database schema --- .../include/mbgl/storage/offline_schema.sql | 164 +++++++++++++++++---- 1 file changed, 134 insertions(+), 30 deletions(-) diff --git a/platform/default/include/mbgl/storage/offline_schema.sql b/platform/default/include/mbgl/storage/offline_schema.sql index 722b0e0451..93f6f2a5ce 100644 --- a/platform/default/include/mbgl/storage/offline_schema.sql +++ b/platform/default/include/mbgl/storage/offline_schema.sql @@ -1,55 +1,159 @@ -CREATE TABLE resources ( -- Generic table for style, source, sprite, and glyph resources. - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - url TEXT NOT NULL, - kind INTEGER NOT NULL, - expires INTEGER, - modified INTEGER, - etag TEXT, - data BLOB, - compressed INTEGER NOT NULL DEFAULT 0, - accessed INTEGER NOT NULL, - must_revalidate INTEGER NOT NULL DEFAULT 0, +-- +-- Table containing the style, source, sprite, and glyph +-- resources. Essentially everything that is not a tile. +-- +CREATE TABLE resources ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Primary key. + + url TEXT NOT NULL, -- The URL of the resource without the access token. If a Mapbox + -- resource, will be stored using the mapbox:// schema. Must be + -- unique and that is enforced by the database schema. + + kind INTEGER NOT NULL, -- Type of the resource, taken from Resource::Kind enumeration: + -- style = 1 + -- source = 2 + -- tile = 3 + -- glyphs = 4 + -- sprite image = 5 + -- sprite JSON = 6 + -- image = 7 + + expires INTEGER, -- Expiration time. The resource will be refreshed after this + -- expiration is reached. + + modified INTEGER, -- Last time the resource was modified. + + etag TEXT, -- Checksum used for cache optimization. If, when refreshing the + -- resource, it matches the etag on the server, the resource will + -- not get re-downloaded. See: + -- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag + + data BLOB, -- Contents of the resource. + + compressed INTEGER NOT NULL DEFAULT 0, -- If the resource is compressed with Deflate or not. Compression is + -- optional and should be used when the compression ratio is + -- significant. Using compression will make decoding time slower + -- because it will add an extra decompression step. + + accessed INTEGER NOT NULL, -- Last time the resource was used by GL Native. Useful for when + -- evicting the least used resources from the cache. + + must_revalidate INTEGER NOT NULL DEFAULT 0, -- When set to true, the resource will not be used unless it gets + -- first revalidated by the server. UNIQUE (url) ); +-- +-- Table containing all tiles, both vector and raster. +-- CREATE TABLE tiles ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - url_template TEXT NOT NULL, - pixel_ratio INTEGER NOT NULL, - z INTEGER NOT NULL, - x INTEGER NOT NULL, - y INTEGER NOT NULL, - expires INTEGER, - modified INTEGER, - etag TEXT, - data BLOB, - compressed INTEGER NOT NULL DEFAULT 0, - accessed INTEGER NOT NULL, - must_revalidate INTEGER NOT NULL DEFAULT 0, + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Primary key. + + url_template TEXT NOT NULL, -- The URL of the resource without the access token and without + -- the tiles id substituted. Mapbox tiles will be stored using + -- the mapbox:// schema. Example: + -- mapbox://tiles/user.dataset/{z}/{x}/{y}.vector.pbf + + pixel_ratio INTEGER NOT NULL, -- The tile pixel ratio, typically 1 for vector tiles. + + z INTEGER NOT NULL, -- The zoom level of the tile. + + x INTEGER NOT NULL, -- The x position of the tile on the tile grid. + + y INTEGER NOT NULL, -- The y position of the tile on the tile grid. + + expires INTEGER, -- Expiration time. The tile will be refreshed after this + -- expiration is reached. Expired tiles can still be rendered, + -- unless must_revalidate is set to true. If an expired tile + -- gets rendered, it will be replaced by a newer version as soon + -- as the network request with a new tile arrives. + + modified INTEGER, -- Last time the tile was modified. + + etag TEXT, -- Checksum used for cache optimization. If, when refreshing the + -- tile, it matches the etag on the server, the tile will not + -- get re-downloaded. See: + -- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag + + data BLOB, -- Contents of the tile. + + compressed INTEGER NOT NULL DEFAULT 0, -- If the tile is compressed with Deflate or not. Compression is + -- optional and should be used when the compression ratio is + -- significant. Using compression will make decoding time slower + -- because it will add an extra decompression step. + + accessed INTEGER NOT NULL, -- Last time the tile was used by GL Native. Useful for when + -- evicting the least used tiles from the cache. + + must_revalidate INTEGER NOT NULL DEFAULT 0, -- When set to true, the tile will not be used unless it gets + -- first revalidated by the server. UNIQUE (url_template, pixel_ratio, z, x, y) ); +-- +-- Regions define the offline regions, which could be a GeoJSON geometry, +-- or a bounding box like this example: +-- +-- { +-- "bounds": [ +-- 37.2, +-- -122.8, +-- 38.1, +-- -121.7 +-- ], +-- "include_ideographs": false, +-- "max_zoom": 15.0, +-- "min_zoom": 0.0, +-- "pixel_ratio": 1.0, +-- "style_url": "mapbox://styles/mapbox/streets-v11" +-- } +-- +-- The semantic definition of the region is up to the user and +-- it could be a city, a country or an arbitrary bounding box. +-- +-- Regions can overlap, which will cause them to share resources +-- when it is the case. +-- +-- "include_ideographs" is set to true when CJK characters are +-- include on the offline package. By default, CJK is rendered +-- by GL Native client side using local fonts. Downloading CJK +-- will increase the size of the database considerably. +-- CREATE TABLE regions ( - id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - definition TEXT NOT NULL, -- JSON formatted definition of region. Regions may be of variant types: - -- e.g. bbox and zoom range, route path, flyTo parameters, etc. Note that - -- the set of tiles required for a region may span multiple sources. - description BLOB -- User provided data in user-defined format + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, -- Primary key. + + definition TEXT NOT NULL, -- JSON formatted definition of a region, a bounding box + -- or a GeoJSON geometry. See https://geojson.org. + + description BLOB -- User provided data in user-defined format. ); +-- +-- Table mapping resources to regions. A resource +-- might be part of many regions. Resources without +-- regions are part of the ambient cache. +-- CREATE TABLE region_resources ( region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE, resource_id INTEGER NOT NULL REFERENCES resources(id), UNIQUE (region_id, resource_id) ); +-- +-- Table mapping tiles to regions. A tile might +-- be part of many regions, meaning that regions might +-- overlap efficiently. Tiles without regions are part +-- of the ambient cache. +-- CREATE TABLE region_tiles ( region_id INTEGER NOT NULL REFERENCES regions(id) ON DELETE CASCADE, tile_id INTEGER NOT NULL REFERENCES tiles(id), UNIQUE (region_id, tile_id) ); --- Indexes for efficient eviction queries +-- +-- Indexes for efficient eviction queries. +-- CREATE INDEX resources_accessed ON resources (accessed); -- cgit v1.2.1 From 0752e26055ff7d1d0fc8ceb11cd0b72775925a9e Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 11 Oct 2019 16:30:24 +0300 Subject: [render-test] Fix bots not running the render tests self checks --- next/render-test/CMakeLists.txt | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 80709d2b89..1a4cd5ceb6 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -51,16 +51,5 @@ add_test( WORKING_DIRECTORY ${MBGL_ROOT} ) -add_test( - NAME mbgl-render-test-probes - COMMAND - mbgl-render-test - render-tests - --recycle-map - --shuffle - --seed=${MBGL_RENDER_TEST_SEED} - --rootPath=render-test - WORKING_DIRECTORY ${MBGL_ROOT} -) - +add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test tests --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT}) add_test(NAME mbgl-query-test COMMAND mbgl-render-test query-tests WORKING_DIRECTORY ${MBGL_ROOT}) -- cgit v1.2.1 From 7f5c63061398e294e1bd79e157e5486ee787c726 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 11 Oct 2019 16:31:15 +0300 Subject: [render-test] Fix UPDATE_METRICS=1 changing the path of file size tests Should use the exact same path as described on style.json --- render-test/runner.cpp | 14 ++++++++------ render-test/tests/filesize/fail-size-is-over/metrics.json | 2 +- render-test/tests/filesize/fail-size-is-under/metrics.json | 2 +- render-test/tests/filesize/pass-size-is-same/metrics.json | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/render-test/runner.cpp b/render-test/runner.cpp index f056902b7f..103a14a079 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -579,20 +579,22 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(operationArray[2].IsString()); std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength()); - mbgl::filesystem::path path = std::string(operationArray[2].GetString(), operationArray[2].GetStringLength()); + std::string path = std::string(operationArray[2].GetString(), operationArray[2].GetStringLength()); assert(!path.empty()); - if (!path.is_absolute()) { - path = metadata.paths.defaultExpectations() / path; + mbgl::filesystem::path filePath(path); + + if (!filePath.is_absolute()) { + filePath = metadata.paths.defaultExpectations() / filePath; } - if (mbgl::filesystem::exists(path)) { - auto size = mbgl::filesystem::file_size(path); + if (mbgl::filesystem::exists(filePath)) { + auto size = mbgl::filesystem::file_size(filePath); metadata.metrics.fileSize.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(mark)), std::forward_as_tuple(std::move(path), size)); } else { - metadata.errorMessage = std::string("File not found: ") + path.string(); + metadata.errorMessage = std::string("File not found: ") + path; return false; } } else if (operationArray[0].GetString() == memoryProbeStartOp) { diff --git a/render-test/tests/filesize/fail-size-is-over/metrics.json b/render-test/tests/filesize/fail-size-is-over/metrics.json index 2df7e7da11..4aa4fe1317 100644 --- a/render-test/tests/filesize/fail-size-is-over/metrics.json +++ b/render-test/tests/filesize/fail-size-is-over/metrics.json @@ -1 +1 @@ -{"fileSize":[["image","../render-test/tests/filesize/fail-size-is-over/expected.png",100],["style","../render-test/tests/filesize/fail-size-is-over/style.json",100]]} +{"fileSize":[["image","expected.png",999],["style","style.json",999]]} diff --git a/render-test/tests/filesize/fail-size-is-under/metrics.json b/render-test/tests/filesize/fail-size-is-under/metrics.json index 92d3f1e3d5..cd657a4cc1 100644 --- a/render-test/tests/filesize/fail-size-is-under/metrics.json +++ b/render-test/tests/filesize/fail-size-is-under/metrics.json @@ -1 +1 @@ -{"fileSize":[["image","../render-test/tests/filesize/fail-size-is-under/expected.png",999],["style","../render-test/tests/filesize/fail-size-is-under/style.json",999]]} +{"fileSize":[["image","expected.png",100],["style","style.json",100]]} diff --git a/render-test/tests/filesize/pass-size-is-same/metrics.json b/render-test/tests/filesize/pass-size-is-same/metrics.json index 4c01d3b2ca..607565213f 100644 --- a/render-test/tests/filesize/pass-size-is-same/metrics.json +++ b/render-test/tests/filesize/pass-size-is-same/metrics.json @@ -1 +1 @@ -{"fileSize":[["image","../render-test/tests/filesize/pass-size-is-same/expected.png",686],["style","../render-test/tests/filesize/pass-size-is-same/style.json",609]]} \ No newline at end of file +{"fileSize":[["image","expected.png",686],["style","style.json",609]]} \ No newline at end of file -- cgit v1.2.1 From acd7fba3d50aca132e2d3ce6fb75279b2d1f3631 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 11 Oct 2019 16:52:22 +0300 Subject: [render-test] Add more probe tests for file size Also make the tests simpler. --- .../filesize/fail-file-doesnt-match/expected.png | Bin 686 -> 169 bytes .../filesize/fail-file-doesnt-match/metrics.json | 1 + .../filesize/fail-file-doesnt-match/style.json | 14 ++++----- .../filesize/fail-file-not-found/expected.png | Bin 0 -> 169 bytes .../tests/filesize/fail-file-not-found/style.json | 32 +++++++++++++++++++++ .../tests/filesize/fail-size-is-over/expected.png | Bin 686 -> 169 bytes .../tests/filesize/fail-size-is-over/style.json | 10 ++----- .../tests/filesize/fail-size-is-under/expected.png | Bin 686 -> 169 bytes .../tests/filesize/fail-size-is-under/style.json | 10 ++----- .../tests/filesize/pass-size-is-same/expected.png | Bin 686 -> 169 bytes .../tests/filesize/pass-size-is-same/metrics.json | 2 +- .../tests/filesize/pass-size-is-same/style.json | 10 ++----- render-test/tests/should-fail.json | 3 +- 13 files changed, 50 insertions(+), 32 deletions(-) create mode 100644 render-test/tests/filesize/fail-file-doesnt-match/metrics.json create mode 100644 render-test/tests/filesize/fail-file-not-found/expected.png create mode 100644 render-test/tests/filesize/fail-file-not-found/style.json diff --git a/render-test/tests/filesize/fail-file-doesnt-match/expected.png b/render-test/tests/filesize/fail-file-doesnt-match/expected.png index feed2e457f..83d01c4e5d 100644 Binary files a/render-test/tests/filesize/fail-file-doesnt-match/expected.png and b/render-test/tests/filesize/fail-file-doesnt-match/expected.png differ diff --git a/render-test/tests/filesize/fail-file-doesnt-match/metrics.json b/render-test/tests/filesize/fail-file-doesnt-match/metrics.json new file mode 100644 index 0000000000..8401ce91e9 --- /dev/null +++ b/render-test/tests/filesize/fail-file-doesnt-match/metrics.json @@ -0,0 +1 @@ +{"fileSize":[["image","foo.123",442],["style","bar.321",609]]} diff --git a/render-test/tests/filesize/fail-file-doesnt-match/style.json b/render-test/tests/filesize/fail-file-doesnt-match/style.json index 91e90ffbe8..a3267fcf5e 100644 --- a/render-test/tests/filesize/fail-file-doesnt-match/style.json +++ b/render-test/tests/filesize/fail-file-doesnt-match/style.json @@ -3,8 +3,8 @@ "metadata": { "test": { "operations": [ - ["probeFileSize", "style", "aaaaa.json"], - ["probeFileSize", "image", "bbbbb.png"] + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] ], "width": 64, "height": 64 @@ -22,15 +22,11 @@ } } }, - "sprite": "local://sprites/sprite", "layers": [ { - "id": "symbol", - "type": "symbol", - "source": "geojson", - "layout": { - "icon-image": "circle-12" - } + "id": "circle", + "type": "circle", + "source": "geojson" } ] } diff --git a/render-test/tests/filesize/fail-file-not-found/expected.png b/render-test/tests/filesize/fail-file-not-found/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/filesize/fail-file-not-found/expected.png differ diff --git a/render-test/tests/filesize/fail-file-not-found/style.json b/render-test/tests/filesize/fail-file-not-found/style.json new file mode 100644 index 0000000000..17dbd1e3d7 --- /dev/null +++ b/render-test/tests/filesize/fail-file-not-found/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.aaaa"], + ["probeFileSize", "image", "expected.bbb"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/filesize/fail-size-is-over/expected.png b/render-test/tests/filesize/fail-size-is-over/expected.png index feed2e457f..83d01c4e5d 100644 Binary files a/render-test/tests/filesize/fail-size-is-over/expected.png and b/render-test/tests/filesize/fail-size-is-over/expected.png differ diff --git a/render-test/tests/filesize/fail-size-is-over/style.json b/render-test/tests/filesize/fail-size-is-over/style.json index ce2069a372..a3267fcf5e 100644 --- a/render-test/tests/filesize/fail-size-is-over/style.json +++ b/render-test/tests/filesize/fail-size-is-over/style.json @@ -22,15 +22,11 @@ } } }, - "sprite": "local://sprites/sprite", "layers": [ { - "id": "symbol", - "type": "symbol", - "source": "geojson", - "layout": { - "icon-image": "circle-12" - } + "id": "circle", + "type": "circle", + "source": "geojson" } ] } diff --git a/render-test/tests/filesize/fail-size-is-under/expected.png b/render-test/tests/filesize/fail-size-is-under/expected.png index feed2e457f..83d01c4e5d 100644 Binary files a/render-test/tests/filesize/fail-size-is-under/expected.png and b/render-test/tests/filesize/fail-size-is-under/expected.png differ diff --git a/render-test/tests/filesize/fail-size-is-under/style.json b/render-test/tests/filesize/fail-size-is-under/style.json index ce2069a372..a3267fcf5e 100644 --- a/render-test/tests/filesize/fail-size-is-under/style.json +++ b/render-test/tests/filesize/fail-size-is-under/style.json @@ -22,15 +22,11 @@ } } }, - "sprite": "local://sprites/sprite", "layers": [ { - "id": "symbol", - "type": "symbol", - "source": "geojson", - "layout": { - "icon-image": "circle-12" - } + "id": "circle", + "type": "circle", + "source": "geojson" } ] } diff --git a/render-test/tests/filesize/pass-size-is-same/expected.png b/render-test/tests/filesize/pass-size-is-same/expected.png index feed2e457f..83d01c4e5d 100644 Binary files a/render-test/tests/filesize/pass-size-is-same/expected.png and b/render-test/tests/filesize/pass-size-is-same/expected.png differ diff --git a/render-test/tests/filesize/pass-size-is-same/metrics.json b/render-test/tests/filesize/pass-size-is-same/metrics.json index 607565213f..cf4bb89dd0 100644 --- a/render-test/tests/filesize/pass-size-is-same/metrics.json +++ b/render-test/tests/filesize/pass-size-is-same/metrics.json @@ -1 +1 @@ -{"fileSize":[["image","expected.png",686],["style","style.json",609]]} \ No newline at end of file +{"fileSize":[["image","expected.png",169],["style","style.json",510]]} \ No newline at end of file diff --git a/render-test/tests/filesize/pass-size-is-same/style.json b/render-test/tests/filesize/pass-size-is-same/style.json index ce2069a372..a3267fcf5e 100644 --- a/render-test/tests/filesize/pass-size-is-same/style.json +++ b/render-test/tests/filesize/pass-size-is-same/style.json @@ -22,15 +22,11 @@ } } }, - "sprite": "local://sprites/sprite", "layers": [ { - "id": "symbol", - "type": "symbol", - "source": "geojson", - "layout": { - "icon-image": "circle-12" - } + "id": "circle", + "type": "circle", + "source": "geojson" } ] } diff --git a/render-test/tests/should-fail.json b/render-test/tests/should-fail.json index 28859d4151..1c3784d473 100644 --- a/render-test/tests/should-fail.json +++ b/render-test/tests/should-fail.json @@ -1,5 +1,6 @@ { "tests/filesize/fail-size-is-over": "Should fail, size is bigger than expected.", "tests/filesize/fail-size-is-under": "Should fail, size is smaller than expected.", - "tests/filesize/fail-file-doesnt-match": "Should fail, file not found." + "tests/filesize/fail-file-doesnt-match": "Should fail, doesn't match the expectation.", + "tests/filesize/fail-file-not-found": "Should fail, file not found." } -- cgit v1.2.1 From 307f9cede112c4c8297adea491f62a82a4dd2b86 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 11 Oct 2019 17:06:37 +0300 Subject: [render-test] Prettyfy metrics output --- render-test/parser.cpp | 2 +- .../tests/filesize/fail-file-doesnt-match/metrics.json | 15 ++++++++++++++- render-test/tests/filesize/fail-size-is-over/metrics.json | 15 ++++++++++++++- .../tests/filesize/fail-size-is-under/metrics.json | 15 ++++++++++++++- render-test/tests/filesize/pass-size-is-same/metrics.json | 15 ++++++++++++++- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 34cccad2a2..aef2f40c16 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -270,7 +270,7 @@ std::string serializeJsonValue(const mbgl::JSValue& value) { std::string serializeMetrics(const TestMetrics& metrics) { rapidjson::StringBuffer s; - rapidjson::Writer writer(s); + rapidjson::PrettyWriter writer(s); writer.StartObject(); diff --git a/render-test/tests/filesize/fail-file-doesnt-match/metrics.json b/render-test/tests/filesize/fail-file-doesnt-match/metrics.json index 8401ce91e9..e02fefc652 100644 --- a/render-test/tests/filesize/fail-file-doesnt-match/metrics.json +++ b/render-test/tests/filesize/fail-file-doesnt-match/metrics.json @@ -1 +1,14 @@ -{"fileSize":[["image","foo.123",442],["style","bar.321",609]]} +{ + "fileSize": [ + [ + "image", + "expected.aaa", + 169 + ], + [ + "style", + "style.bbbb", + 510 + ] + ] +} diff --git a/render-test/tests/filesize/fail-size-is-over/metrics.json b/render-test/tests/filesize/fail-size-is-over/metrics.json index 4aa4fe1317..07cd3b42c0 100644 --- a/render-test/tests/filesize/fail-size-is-over/metrics.json +++ b/render-test/tests/filesize/fail-size-is-over/metrics.json @@ -1 +1,14 @@ -{"fileSize":[["image","expected.png",999],["style","style.json",999]]} +{ + "fileSize": [ + [ + "image", + "expected.png", + 999 + ], + [ + "style", + "style.json", + 999 + ] + ] +} diff --git a/render-test/tests/filesize/fail-size-is-under/metrics.json b/render-test/tests/filesize/fail-size-is-under/metrics.json index cd657a4cc1..f09728b5b3 100644 --- a/render-test/tests/filesize/fail-size-is-under/metrics.json +++ b/render-test/tests/filesize/fail-size-is-under/metrics.json @@ -1 +1,14 @@ -{"fileSize":[["image","expected.png",100],["style","style.json",100]]} +{ + "fileSize": [ + [ + "image", + "expected.png", + 100 + ], + [ + "style", + "style.json", + 100 + ] + ] +} diff --git a/render-test/tests/filesize/pass-size-is-same/metrics.json b/render-test/tests/filesize/pass-size-is-same/metrics.json index cf4bb89dd0..82288122b8 100644 --- a/render-test/tests/filesize/pass-size-is-same/metrics.json +++ b/render-test/tests/filesize/pass-size-is-same/metrics.json @@ -1 +1,14 @@ -{"fileSize":[["image","expected.png",169],["style","style.json",510]]} \ No newline at end of file +{ + "fileSize": [ + [ + "image", + "expected.png", + 169 + ], + [ + "style", + "style.json", + 510 + ] + ] +} \ No newline at end of file -- cgit v1.2.1 From 2fb1e47b75c038f226397df7b790ba699b6e2dc8 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Fri, 11 Oct 2019 17:22:30 +0300 Subject: [render-test] No camelCase on the metrics.json tag It is ugly. --- render-test/parser.cpp | 8 +++--- .../file-size/fail-file-doesnt-match/expected.png | Bin 0 -> 169 bytes .../file-size/fail-file-doesnt-match/metrics.json | 14 +++++++++ .../file-size/fail-file-doesnt-match/style.json | 32 +++++++++++++++++++++ .../file-size/fail-file-not-found/expected.png | Bin 0 -> 169 bytes .../tests/file-size/fail-file-not-found/style.json | 32 +++++++++++++++++++++ .../tests/file-size/fail-size-is-over/expected.png | Bin 0 -> 169 bytes .../tests/file-size/fail-size-is-over/metrics.json | 14 +++++++++ .../tests/file-size/fail-size-is-over/style.json | 32 +++++++++++++++++++++ .../file-size/fail-size-is-under/expected.png | Bin 0 -> 169 bytes .../file-size/fail-size-is-under/metrics.json | 14 +++++++++ .../tests/file-size/fail-size-is-under/style.json | 32 +++++++++++++++++++++ .../tests/file-size/pass-size-is-same/expected.png | Bin 0 -> 169 bytes .../tests/file-size/pass-size-is-same/metrics.json | 14 +++++++++ .../tests/file-size/pass-size-is-same/style.json | 32 +++++++++++++++++++++ .../filesize/fail-file-doesnt-match/expected.png | Bin 169 -> 0 bytes .../filesize/fail-file-doesnt-match/metrics.json | 14 --------- .../filesize/fail-file-doesnt-match/style.json | 32 --------------------- .../filesize/fail-file-not-found/expected.png | Bin 169 -> 0 bytes .../tests/filesize/fail-file-not-found/style.json | 32 --------------------- .../tests/filesize/fail-size-is-over/expected.png | Bin 169 -> 0 bytes .../tests/filesize/fail-size-is-over/metrics.json | 14 --------- .../tests/filesize/fail-size-is-over/style.json | 32 --------------------- .../tests/filesize/fail-size-is-under/expected.png | Bin 169 -> 0 bytes .../tests/filesize/fail-size-is-under/metrics.json | 14 --------- .../tests/filesize/fail-size-is-under/style.json | 32 --------------------- .../tests/filesize/pass-size-is-same/expected.png | Bin 169 -> 0 bytes .../tests/filesize/pass-size-is-same/metrics.json | 14 --------- .../tests/filesize/pass-size-is-same/style.json | 32 --------------------- render-test/tests/should-fail.json | 8 +++--- 30 files changed, 224 insertions(+), 224 deletions(-) create mode 100644 render-test/tests/file-size/fail-file-doesnt-match/expected.png create mode 100644 render-test/tests/file-size/fail-file-doesnt-match/metrics.json create mode 100644 render-test/tests/file-size/fail-file-doesnt-match/style.json create mode 100644 render-test/tests/file-size/fail-file-not-found/expected.png create mode 100644 render-test/tests/file-size/fail-file-not-found/style.json create mode 100644 render-test/tests/file-size/fail-size-is-over/expected.png create mode 100644 render-test/tests/file-size/fail-size-is-over/metrics.json create mode 100644 render-test/tests/file-size/fail-size-is-over/style.json create mode 100644 render-test/tests/file-size/fail-size-is-under/expected.png create mode 100644 render-test/tests/file-size/fail-size-is-under/metrics.json create mode 100644 render-test/tests/file-size/fail-size-is-under/style.json create mode 100644 render-test/tests/file-size/pass-size-is-same/expected.png create mode 100644 render-test/tests/file-size/pass-size-is-same/metrics.json create mode 100644 render-test/tests/file-size/pass-size-is-same/style.json delete mode 100644 render-test/tests/filesize/fail-file-doesnt-match/expected.png delete mode 100644 render-test/tests/filesize/fail-file-doesnt-match/metrics.json delete mode 100644 render-test/tests/filesize/fail-file-doesnt-match/style.json delete mode 100644 render-test/tests/filesize/fail-file-not-found/expected.png delete mode 100644 render-test/tests/filesize/fail-file-not-found/style.json delete mode 100644 render-test/tests/filesize/fail-size-is-over/expected.png delete mode 100644 render-test/tests/filesize/fail-size-is-over/metrics.json delete mode 100644 render-test/tests/filesize/fail-size-is-over/style.json delete mode 100644 render-test/tests/filesize/fail-size-is-under/expected.png delete mode 100644 render-test/tests/filesize/fail-size-is-under/metrics.json delete mode 100644 render-test/tests/filesize/fail-size-is-under/style.json delete mode 100644 render-test/tests/filesize/pass-size-is-same/expected.png delete mode 100644 render-test/tests/filesize/pass-size-is-same/metrics.json delete mode 100644 render-test/tests/filesize/pass-size-is-same/style.json diff --git a/render-test/parser.cpp b/render-test/parser.cpp index aef2f40c16..cbbc43293a 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -274,9 +274,9 @@ std::string serializeMetrics(const TestMetrics& metrics) { writer.StartObject(); - // Start fileSize section. + // Start file-size section. if (!metrics.fileSize.empty()) { - writer.Key("fileSize"); + writer.Key("file-size"); writer.StartArray(); for (const auto& fileSizeProbe : metrics.fileSize) { assert(!fileSizeProbe.first.empty()); @@ -460,8 +460,8 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { const auto& document = maybeJson.get(); - if (document.HasMember("fileSize")) { - const mbgl::JSValue& fileSizeValue = document["fileSize"]; + if (document.HasMember("file-size")) { + const mbgl::JSValue& fileSizeValue = document["file-size"]; assert(fileSizeValue.IsArray()); for (auto& probeValue : fileSizeValue.GetArray()) { assert(probeValue.IsArray()); diff --git a/render-test/tests/file-size/fail-file-doesnt-match/expected.png b/render-test/tests/file-size/fail-file-doesnt-match/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/fail-file-doesnt-match/expected.png differ diff --git a/render-test/tests/file-size/fail-file-doesnt-match/metrics.json b/render-test/tests/file-size/fail-file-doesnt-match/metrics.json new file mode 100644 index 0000000000..c0002163d6 --- /dev/null +++ b/render-test/tests/file-size/fail-file-doesnt-match/metrics.json @@ -0,0 +1,14 @@ +{ + "file-size": [ + [ + "image", + "expected.aaa", + 169 + ], + [ + "style", + "style.bbbb", + 510 + ] + ] +} diff --git a/render-test/tests/file-size/fail-file-doesnt-match/style.json b/render-test/tests/file-size/fail-file-doesnt-match/style.json new file mode 100644 index 0000000000..a3267fcf5e --- /dev/null +++ b/render-test/tests/file-size/fail-file-doesnt-match/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/file-size/fail-file-not-found/expected.png b/render-test/tests/file-size/fail-file-not-found/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/fail-file-not-found/expected.png differ diff --git a/render-test/tests/file-size/fail-file-not-found/style.json b/render-test/tests/file-size/fail-file-not-found/style.json new file mode 100644 index 0000000000..17dbd1e3d7 --- /dev/null +++ b/render-test/tests/file-size/fail-file-not-found/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.aaaa"], + ["probeFileSize", "image", "expected.bbb"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/file-size/fail-size-is-over/expected.png b/render-test/tests/file-size/fail-size-is-over/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/fail-size-is-over/expected.png differ diff --git a/render-test/tests/file-size/fail-size-is-over/metrics.json b/render-test/tests/file-size/fail-size-is-over/metrics.json new file mode 100644 index 0000000000..bc194081cf --- /dev/null +++ b/render-test/tests/file-size/fail-size-is-over/metrics.json @@ -0,0 +1,14 @@ +{ + "file-size": [ + [ + "image", + "expected.png", + 999 + ], + [ + "style", + "style.json", + 999 + ] + ] +} diff --git a/render-test/tests/file-size/fail-size-is-over/style.json b/render-test/tests/file-size/fail-size-is-over/style.json new file mode 100644 index 0000000000..a3267fcf5e --- /dev/null +++ b/render-test/tests/file-size/fail-size-is-over/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/file-size/fail-size-is-under/expected.png b/render-test/tests/file-size/fail-size-is-under/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/fail-size-is-under/expected.png differ diff --git a/render-test/tests/file-size/fail-size-is-under/metrics.json b/render-test/tests/file-size/fail-size-is-under/metrics.json new file mode 100644 index 0000000000..d288c2ceee --- /dev/null +++ b/render-test/tests/file-size/fail-size-is-under/metrics.json @@ -0,0 +1,14 @@ +{ + "file-size": [ + [ + "image", + "expected.png", + 100 + ], + [ + "style", + "style.json", + 100 + ] + ] +} diff --git a/render-test/tests/file-size/fail-size-is-under/style.json b/render-test/tests/file-size/fail-size-is-under/style.json new file mode 100644 index 0000000000..a3267fcf5e --- /dev/null +++ b/render-test/tests/file-size/fail-size-is-under/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/file-size/pass-size-is-same/expected.png b/render-test/tests/file-size/pass-size-is-same/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/pass-size-is-same/expected.png differ diff --git a/render-test/tests/file-size/pass-size-is-same/metrics.json b/render-test/tests/file-size/pass-size-is-same/metrics.json new file mode 100644 index 0000000000..b98328f72e --- /dev/null +++ b/render-test/tests/file-size/pass-size-is-same/metrics.json @@ -0,0 +1,14 @@ +{ + "file-size": [ + [ + "image", + "expected.png", + 169 + ], + [ + "style", + "style.json", + 510 + ] + ] +} \ No newline at end of file diff --git a/render-test/tests/file-size/pass-size-is-same/style.json b/render-test/tests/file-size/pass-size-is-same/style.json new file mode 100644 index 0000000000..a3267fcf5e --- /dev/null +++ b/render-test/tests/file-size/pass-size-is-same/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json"], + ["probeFileSize", "image", "expected.png"] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/filesize/fail-file-doesnt-match/expected.png b/render-test/tests/filesize/fail-file-doesnt-match/expected.png deleted file mode 100644 index 83d01c4e5d..0000000000 Binary files a/render-test/tests/filesize/fail-file-doesnt-match/expected.png and /dev/null differ diff --git a/render-test/tests/filesize/fail-file-doesnt-match/metrics.json b/render-test/tests/filesize/fail-file-doesnt-match/metrics.json deleted file mode 100644 index e02fefc652..0000000000 --- a/render-test/tests/filesize/fail-file-doesnt-match/metrics.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "fileSize": [ - [ - "image", - "expected.aaa", - 169 - ], - [ - "style", - "style.bbbb", - 510 - ] - ] -} diff --git a/render-test/tests/filesize/fail-file-doesnt-match/style.json b/render-test/tests/filesize/fail-file-doesnt-match/style.json deleted file mode 100644 index a3267fcf5e..0000000000 --- a/render-test/tests/filesize/fail-file-doesnt-match/style.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] - ], - "width": 64, - "height": 64 - } - }, - "sources": { - "geojson": { - "type": "geojson", - "data": { - "type": "Point", - "coordinates": [ - 0, - 0 - ] - } - } - }, - "layers": [ - { - "id": "circle", - "type": "circle", - "source": "geojson" - } - ] -} diff --git a/render-test/tests/filesize/fail-file-not-found/expected.png b/render-test/tests/filesize/fail-file-not-found/expected.png deleted file mode 100644 index 83d01c4e5d..0000000000 Binary files a/render-test/tests/filesize/fail-file-not-found/expected.png and /dev/null differ diff --git a/render-test/tests/filesize/fail-file-not-found/style.json b/render-test/tests/filesize/fail-file-not-found/style.json deleted file mode 100644 index 17dbd1e3d7..0000000000 --- a/render-test/tests/filesize/fail-file-not-found/style.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "operations": [ - ["probeFileSize", "style", "style.aaaa"], - ["probeFileSize", "image", "expected.bbb"] - ], - "width": 64, - "height": 64 - } - }, - "sources": { - "geojson": { - "type": "geojson", - "data": { - "type": "Point", - "coordinates": [ - 0, - 0 - ] - } - } - }, - "layers": [ - { - "id": "circle", - "type": "circle", - "source": "geojson" - } - ] -} diff --git a/render-test/tests/filesize/fail-size-is-over/expected.png b/render-test/tests/filesize/fail-size-is-over/expected.png deleted file mode 100644 index 83d01c4e5d..0000000000 Binary files a/render-test/tests/filesize/fail-size-is-over/expected.png and /dev/null differ diff --git a/render-test/tests/filesize/fail-size-is-over/metrics.json b/render-test/tests/filesize/fail-size-is-over/metrics.json deleted file mode 100644 index 07cd3b42c0..0000000000 --- a/render-test/tests/filesize/fail-size-is-over/metrics.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "fileSize": [ - [ - "image", - "expected.png", - 999 - ], - [ - "style", - "style.json", - 999 - ] - ] -} diff --git a/render-test/tests/filesize/fail-size-is-over/style.json b/render-test/tests/filesize/fail-size-is-over/style.json deleted file mode 100644 index a3267fcf5e..0000000000 --- a/render-test/tests/filesize/fail-size-is-over/style.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] - ], - "width": 64, - "height": 64 - } - }, - "sources": { - "geojson": { - "type": "geojson", - "data": { - "type": "Point", - "coordinates": [ - 0, - 0 - ] - } - } - }, - "layers": [ - { - "id": "circle", - "type": "circle", - "source": "geojson" - } - ] -} diff --git a/render-test/tests/filesize/fail-size-is-under/expected.png b/render-test/tests/filesize/fail-size-is-under/expected.png deleted file mode 100644 index 83d01c4e5d..0000000000 Binary files a/render-test/tests/filesize/fail-size-is-under/expected.png and /dev/null differ diff --git a/render-test/tests/filesize/fail-size-is-under/metrics.json b/render-test/tests/filesize/fail-size-is-under/metrics.json deleted file mode 100644 index f09728b5b3..0000000000 --- a/render-test/tests/filesize/fail-size-is-under/metrics.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "fileSize": [ - [ - "image", - "expected.png", - 100 - ], - [ - "style", - "style.json", - 100 - ] - ] -} diff --git a/render-test/tests/filesize/fail-size-is-under/style.json b/render-test/tests/filesize/fail-size-is-under/style.json deleted file mode 100644 index a3267fcf5e..0000000000 --- a/render-test/tests/filesize/fail-size-is-under/style.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] - ], - "width": 64, - "height": 64 - } - }, - "sources": { - "geojson": { - "type": "geojson", - "data": { - "type": "Point", - "coordinates": [ - 0, - 0 - ] - } - } - }, - "layers": [ - { - "id": "circle", - "type": "circle", - "source": "geojson" - } - ] -} diff --git a/render-test/tests/filesize/pass-size-is-same/expected.png b/render-test/tests/filesize/pass-size-is-same/expected.png deleted file mode 100644 index 83d01c4e5d..0000000000 Binary files a/render-test/tests/filesize/pass-size-is-same/expected.png and /dev/null differ diff --git a/render-test/tests/filesize/pass-size-is-same/metrics.json b/render-test/tests/filesize/pass-size-is-same/metrics.json deleted file mode 100644 index 82288122b8..0000000000 --- a/render-test/tests/filesize/pass-size-is-same/metrics.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "fileSize": [ - [ - "image", - "expected.png", - 169 - ], - [ - "style", - "style.json", - 510 - ] - ] -} \ No newline at end of file diff --git a/render-test/tests/filesize/pass-size-is-same/style.json b/render-test/tests/filesize/pass-size-is-same/style.json deleted file mode 100644 index a3267fcf5e..0000000000 --- a/render-test/tests/filesize/pass-size-is-same/style.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": 8, - "metadata": { - "test": { - "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] - ], - "width": 64, - "height": 64 - } - }, - "sources": { - "geojson": { - "type": "geojson", - "data": { - "type": "Point", - "coordinates": [ - 0, - 0 - ] - } - } - }, - "layers": [ - { - "id": "circle", - "type": "circle", - "source": "geojson" - } - ] -} diff --git a/render-test/tests/should-fail.json b/render-test/tests/should-fail.json index 1c3784d473..30c91836a7 100644 --- a/render-test/tests/should-fail.json +++ b/render-test/tests/should-fail.json @@ -1,6 +1,6 @@ { - "tests/filesize/fail-size-is-over": "Should fail, size is bigger than expected.", - "tests/filesize/fail-size-is-under": "Should fail, size is smaller than expected.", - "tests/filesize/fail-file-doesnt-match": "Should fail, doesn't match the expectation.", - "tests/filesize/fail-file-not-found": "Should fail, file not found." + "tests/file-size/fail-size-is-over": "Should fail, size is bigger than expected.", + "tests/file-size/fail-size-is-under": "Should fail, size is smaller than expected.", + "tests/file-size/fail-file-doesnt-match": "Should fail, doesn't match the expectation.", + "tests/file-size/fail-file-not-found": "Should fail, file not found." } -- cgit v1.2.1 From a1f124c39442d76af77a5aa63bba5afa4f4d6d26 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Fri, 11 Oct 2019 15:16:12 -0400 Subject: [ios] Fix for iOS 9 crash (seen in simulator) (#15771) * [ios] Fix for iOS 9 crash (seen in simulator) * [ios] Update change log * [ios, macos] Add #if around new function. --- platform/darwin/src/MGLSDKMetricsManager.m | 28 +++++++++++++++++++++++++++- platform/ios/CHANGELOG.md | 1 + 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/platform/darwin/src/MGLSDKMetricsManager.m b/platform/darwin/src/MGLSDKMetricsManager.m index 828fbcd505..0ef9ecda10 100644 --- a/platform/darwin/src/MGLSDKMetricsManager.m +++ b/platform/darwin/src/MGLSDKMetricsManager.m @@ -18,6 +18,23 @@ NSString* MGLStringFromMetricType(MGLMetricType metricType) { return eventName; } +// Taken verbatim from NXFreeArchInfo header documentation +#if TARGET_OS_IOS +static void MGLFreeArchInfo(const NXArchInfo *x) +{ + const NXArchInfo *p; + + p = NXGetAllArchInfos(); + while(p->name != NULL){ + if(x == p) + return; + p++; + } + free((char *)x->description); + free((NXArchInfo *)x); +} +#endif + @interface MGLMetricsManager() @property (strong, nonatomic) NSDictionary *metadata; @@ -54,7 +71,16 @@ NSString* MGLStringFromMetricType(MGLMetricType metricType) { if (localArchInfo) { abi = @(localArchInfo->description); - NXFreeArchInfo(localArchInfo); + + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + + // Although NXFreeArchInfo appears to be weakly linked, it does + // not have the weak_import attribute, so check the OS version. + if (&NXFreeArchInfo && [processInfo isOperatingSystemAtLeastVersion:(NSOperatingSystemVersion){10, 0, 0}]) { + NXFreeArchInfo(localArchInfo); + } else { + MGLFreeArchInfo(localArchInfo); + } } } diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index b3eab70c60..5a7235b25a 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -22,6 +22,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed an issue that cause `-[MGLMapView setCamere:withDuration:animationTimingFunction:edgePadding:completionHandler:]` persist the value of `edgePadding`. ([#15584](https://github.com/mapbox/mapbox-gl-native/pull/15584)) * Added `MGLMapView.automaticallyAdjustsContentInset` property that indicates if wether the map view should automatically adjust its content insets. ([#15584](https://github.com/mapbox/mapbox-gl-native/pull/15584)) * Fixed an issue that caused `MGLScaleBar` to have an incorrect size when resizing or rotating. ([#15703](https://github.com/mapbox/mapbox-gl-native/pull/15703)) +* Fixed crash at launch seen on iOS 9 simulator. ([#15771](https://github.com/mapbox/mapbox-gl-native/pull/15771)) ## 5.4.0 - September 25, 2019 -- cgit v1.2.1 From e4e2a78033f25fd966fa9cbbd2babb7e7b499e18 Mon Sep 17 00:00:00 2001 From: Jordan Kiley Date: Fri, 11 Oct 2019 13:46:41 -0700 Subject: Add iOS bindings for cluster properties (#15515) --- platform/darwin/src/MGLShapeSource.h | 32 +++++++++++++ platform/darwin/src/MGLShapeSource.mm | 53 +++++++++++++++++++++ platform/darwin/src/MGLStyleValue.mm | 13 +++++ platform/darwin/src/MGLStyleValue_Private.h | 5 ++ platform/darwin/src/NSExpression+MGLAdditions.h | 7 +++ platform/darwin/src/NSExpression+MGLAdditions.mm | 43 ++++++++++++++--- .../darwin/test/MGLDocumentationExampleTests.swift | 34 ++++++++++++- platform/darwin/test/MGLExpressionTests.mm | 55 ++++++++++++++++++++++ platform/darwin/test/MGLShapeSourceTests.mm | 5 ++ platform/ios/CHANGELOG.md | 4 ++ src/mbgl/style/sources/geojson_source_impl.cpp | 1 + 11 files changed, 244 insertions(+), 8 deletions(-) diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h index a57b963c63..675c219300 100644 --- a/platform/darwin/src/MGLShapeSource.h +++ b/platform/darwin/src/MGLShapeSource.h @@ -41,6 +41,38 @@ FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClus */ FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius; +/** + An `NSDictionary` object where the key is an `NSString`. The dictionary key will + be the feature attribute key. The resulting attribute value is + aggregated from the clustered points. The dictionary value is an `NSArray` + consisting of two `NSExpression` objects. + + The first object determines how the attribute values are accumulated from the + cluster points. It is an `NSExpression` with an expression function that accepts + two or more arguments, such as `sum` or `max`. The arguments should be + `featureAccumulated` and the previously defined feature attribute key. The + resulting value is assigned to the specified attribute key. + + The second `NSExpression` in the array determines which + attribute values are accessed from individual features within a cluster. + + ```swift + let firstExpression = NSExpression(format: "sum:({$featureAccumulated, sumValue})") + let secondExpression = NSExpression(forKeyPath: "magnitude") + let clusterPropertiesDictionary = ["sumValue" : [firstExpression, secondExpression]] + + let options : [MGLShapeSourceOption : Any] = [.clustered : true, + .clusterProperties: clusterPropertiesDictionary] + ``` + + This option corresponds to the + clusterProperties + source property in the Mapbox Style Specification. + + This option only affects point features within an `MGLShapeSource` object; it + is ignored when creating an `MGLComputedShapeSource` object. + */ +FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClusterProperties; /** An `NSNumber` object containing an integer; specifies the maximum zoom level at which to cluster points if clustering is enabled. Defaults to one zoom level diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm index 3628a0eb74..3820fe9d60 100644 --- a/platform/darwin/src/MGLShapeSource.mm +++ b/platform/darwin/src/MGLShapeSource.mm @@ -3,6 +3,7 @@ #import "MGLLoggingConfiguration_Private.h" #import "MGLStyle_Private.h" +#import "MGLStyleValue_Private.h" #import "MGLMapView_Private.h" #import "MGLSource_Private.h" #import "MGLFeature_Private.h" @@ -19,6 +20,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionBuffer = @"MGLShapeSourceOptionBuffer"; const MGLShapeSourceOption MGLShapeSourceOptionClusterRadius = @"MGLShapeSourceOptionClusterRadius"; const MGLShapeSourceOption MGLShapeSourceOptionClustered = @"MGLShapeSourceOptionClustered"; +const MGLShapeSourceOption MGLShapeSourceOptionClusterProperties = @"MGLShapeSourceOptionClusterProperties"; const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSourceOptionMaximumZoomLevel"; const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering"; const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel"; @@ -84,6 +86,57 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClusterProperties must be an NSDictionary with an NSString as a key and an array containing two NSExpression objects as a value."]; + } + + NSEnumerator *stringEnumerator = [value keyEnumerator]; + NSString *key; + + while (key = [stringEnumerator nextObject]) { + NSArray *expressionsArray = value[key]; + if (![expressionsArray isKindOfClass:[NSArray class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClusterProperties dictionary member value must be an array containing two objects."]; + } + // Check that the array has 2 values. One should be a the reduce expression and one should be the map expression. + if ([expressionsArray count] != 2) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClusterProperties member value requires array of two objects."]; + } + + // reduceExpression should be a valid NSExpression + NSExpression *reduceExpression = expressionsArray[0]; + if (![reduceExpression isKindOfClass:[NSExpression class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClusterProperties array value requires two expression objects."]; + } + auto reduce = MGLClusterPropertyFromNSExpression(reduceExpression); + if (!reduce) { + [NSException raise:NSInvalidArgumentException + format:@"Failed to convert MGLShapeSourceOptionClusterProperties reduce expression."]; + } + + // mapExpression should be a valid NSExpression + NSExpression *mapExpression = expressionsArray[1]; + if (![mapExpression isKindOfClass:[NSExpression class]]) { + [NSException raise:NSInvalidArgumentException + format:@"MGLShapeSourceOptionClusterProperties member value must contain a valid NSExpression."]; + } + auto map = MGLClusterPropertyFromNSExpression(mapExpression); + if (!map) { + [NSException raise:NSInvalidArgumentException + format:@"Failed to convert MGLShapeSourceOptionClusterProperties map expression."]; + } + + std::string keyString = std::string([key UTF8String]); + + geoJSONOptions.clusterProperties.emplace(keyString, std::make_pair(std::move(map), std::move(reduce))); + } + } + if (NSNumber *value = options[MGLShapeSourceOptionLineDistanceMetrics]) { if (![value isKindOfClass:[NSNumber class]]) { [NSException raise:NSInvalidArgumentException diff --git a/platform/darwin/src/MGLStyleValue.mm b/platform/darwin/src/MGLStyleValue.mm index 5103b5f5cf..01ad108d7f 100644 --- a/platform/darwin/src/MGLStyleValue.mm +++ b/platform/darwin/src/MGLStyleValue.mm @@ -44,3 +44,16 @@ id MGLJSONObjectFromMBGLValue(const mbgl::Value &value) { id MGLJSONObjectFromMBGLExpression(const mbgl::style::expression::Expression &mbglExpression) { return MGLJSONObjectFromMBGLValue(mbglExpression.serialize()); } + + +std::unique_ptr MGLClusterPropertyFromNSExpression(NSExpression *expression) { + if (!expression) { + return nullptr; + } + + NSArray *jsonExpression = expression.mgl_jsonExpressionObject; + + auto expr = mbgl::style::expression::dsl::createExpression(mbgl::style::conversion::makeConvertible(jsonExpression)); + + return expr; +} diff --git a/platform/darwin/src/MGLStyleValue_Private.h b/platform/darwin/src/MGLStyleValue_Private.h index 376bf5e73b..82ce232c6b 100644 --- a/platform/darwin/src/MGLStyleValue_Private.h +++ b/platform/darwin/src/MGLStyleValue_Private.h @@ -12,12 +12,15 @@ #include #include #include +#include #import #import #import #include +#include + #if TARGET_OS_IPHONE #import "UIColor+MGLAdditions.h" #else @@ -45,6 +48,8 @@ NS_INLINE mbgl::style::TransitionOptions MGLOptionsFromTransition(MGLTransition return options; } +std::unique_ptr MGLClusterPropertyFromNSExpression(NSExpression *expression); + id MGLJSONObjectFromMBGLExpression(const mbgl::style::expression::Expression &mbglExpression); template diff --git a/platform/darwin/src/NSExpression+MGLAdditions.h b/platform/darwin/src/NSExpression+MGLAdditions.h index 2a33367e9c..2109310e69 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.h +++ b/platform/darwin/src/NSExpression+MGLAdditions.h @@ -84,6 +84,13 @@ FOUNDATION_EXTERN MGL_EXPORT const MGLExpressionInterpolationMode MGLExpressionI */ @property (class, nonatomic, readonly) NSExpression *featureIdentifierVariableExpression; +/** + `NSExpression` variable that corresponds to the + id + expression operator in the Mapbox Style Specification. + */ +@property (class, nonatomic, readonly) NSExpression *featureAccumulatedVariableExpression; + /** `NSExpression` variable that corresponds to the properties diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm index 2ca4e0ed88..f139b86a88 100644 --- a/platform/darwin/src/NSExpression+MGLAdditions.mm +++ b/platform/darwin/src/NSExpression+MGLAdditions.mm @@ -553,6 +553,10 @@ const MGLExpressionInterpolationMode MGLExpressionInterpolationModeCubicBezier = return [NSExpression expressionForVariable:@"lineProgress"]; } ++ (NSExpression *)featureAccumulatedVariableExpression { + return [NSExpression expressionForVariable:@"featureAccumulated"]; +} + + (NSExpression *)geometryTypeVariableExpression { return [NSExpression expressionForVariable:@"geometryType"]; } @@ -648,7 +652,6 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { @"let": @"MGL_LET", }; }); - if (!object || object == [NSNull null]) { return [NSExpression expressionForConstantValue:nil]; } @@ -667,11 +670,10 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { }]; return [NSExpression expressionForConstantValue:dictionary]; } - if ([object isKindOfClass:[NSArray class]]) { NSArray *array = (NSArray *)object; NSString *op = array.firstObject; - + if (![op isKindOfClass:[NSString class]]) { NSArray *subexpressions = MGLSubexpressionsWithJSONObjects(array); return [NSExpression expressionForFunction:@"MGL_FUNCTION" arguments:subexpressions]; @@ -839,6 +841,8 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { return NSExpression.heatmapDensityVariableExpression; } else if ([op isEqualToString:@"line-progress"]) { return NSExpression.lineProgressVariableExpression; + } else if ([op isEqualToString:@"accumulated"]) { + return NSExpression.featureAccumulatedVariableExpression; } else if ([op isEqualToString:@"geometry-type"]) { return NSExpression.geometryTypeVariableExpression; } else if ([op isEqualToString:@"id"]) { @@ -961,6 +965,9 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { if ([self.variable isEqualToString:@"zoomLevel"]) { return @[@"zoom"]; } + if ([self.variable isEqualToString:@"featureAccumulated"]) { + return @[@"accumulated"]; + } if ([self.variable isEqualToString:@"geometryType"]) { return @[@"geometry-type"]; } @@ -1046,6 +1053,8 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { case NSFunctionExpressionType: { NSString *function = self.function; + + BOOL hasCollectionProperty = !( ! [self.arguments.firstObject isKindOfClass: [NSExpression class]] || self.arguments.firstObject.expressionType != NSAggregateExpressionType || self.arguments.firstObject.expressionType == NSSubqueryExpressionType); NSString *op = MGLExpressionOperatorsByFunctionNames[function]; if (op) { NSArray *arguments = self.arguments.mgl_jsonExpressionObject; @@ -1057,16 +1066,31 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { NSExpression *count = [NSExpression expressionForFunction:@"count:" arguments:self.arguments]; return [NSExpression expressionForFunction:@"divide:by:" arguments:@[sum, count]].mgl_jsonExpressionObject; } else if ([function isEqualToString:@"sum:"]) { - NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + NSArray *arguments; + if (hasCollectionProperty) { + arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + } else { + arguments = [self.arguments valueForKeyPath:@"mgl_jsonExpressionObject"]; + } return [@[@"+"] arrayByAddingObjectsFromArray:arguments]; } else if ([function isEqualToString:@"count:"]) { NSArray *arguments = self.arguments.firstObject.mgl_jsonExpressionObject; return @[@"length", arguments]; } else if ([function isEqualToString:@"min:"]) { - NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + NSArray *arguments; + if (!hasCollectionProperty) { + arguments = [self.arguments valueForKeyPath:@"mgl_jsonExpressionObject"]; + } else { + arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + } return [@[@"min"] arrayByAddingObjectsFromArray:arguments]; } else if ([function isEqualToString:@"max:"]) { - NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + NSArray *arguments; + if (!hasCollectionProperty) { + arguments = [self.arguments valueForKeyPath:@"mgl_jsonExpressionObject"]; + } else { + arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + } return [@[@"max"] arrayByAddingObjectsFromArray:arguments]; } else if ([function isEqualToString:@"exp:"]) { return [NSExpression expressionForFunction:@"raise:toPower:" arguments:@[@(M_E), self.arguments.firstObject]].mgl_jsonExpressionObject; @@ -1074,7 +1098,12 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) { return [NSExpression expressionWithFormat:@"%@ - modulus:by:(%@, 1)", self.arguments.firstObject, self.arguments.firstObject].mgl_jsonExpressionObject; } else if ([function isEqualToString:@"mgl_join:"]) { - NSArray *arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + NSArray *arguments; + if (!hasCollectionProperty) { + arguments = [self.arguments valueForKeyPath:@"mgl_jsonExpressionObject"]; + } else { + arguments = [self.arguments.firstObject.collection valueForKeyPath:@"mgl_jsonExpressionObject"]; + } return [@[@"concat"] arrayByAddingObjectsFromArray:arguments]; } else if ([function isEqualToString:@"stringByAppendingString:"]) { NSArray *arguments = self.arguments.mgl_jsonExpressionObject; diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift index 9fbb0cc329..7d6bdbed54 100644 --- a/platform/darwin/test/MGLDocumentationExampleTests.swift +++ b/platform/darwin/test/MGLDocumentationExampleTests.swift @@ -554,7 +554,39 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate { XCTAssertNotNil(attributedExpression) } - + + func testMGLShapeSourceOptionClusterProperties() { + //#-example-code + let firstExpression = NSExpression(format: "sum:({$featureAccumulated, sumValue})") + let secondExpression = NSExpression(forKeyPath: "magnitude") + let clusterPropertiesDictionary = ["sumValue" : [firstExpression, secondExpression]] + + let options : [MGLShapeSourceOption : Any] = [.clustered : true, + .clusterProperties: clusterPropertiesDictionary] + //#-end-example-code + let geoJSON: [String: Any] = [ + "type" : "Feature", + "geometry" : [ + "coordinates" : [ + -77.00896639534831, + 38.87031006108791, + 0.0 + ], + "type" : "Point" + ], + "properties" : [ + "cluster" : true, + "cluster_id" : 123, + "point_count" : 4567, + ] + ] + + let clusterShapeData = try! JSONSerialization.data(withJSONObject: geoJSON, options: []) + let shape = try! MGLShape(data: clusterShapeData, encoding: String.Encoding.utf8.rawValue) + let source = MGLShapeSource(identifier: "source", shape: shape, options: options) + mapView.style?.addSource(source) + + } // For testMGLMapView(). func myCustomFunction() {} } diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm index f1fe3ea878..4ccd7adb6e 100644 --- a/platform/darwin/test/MGLExpressionTests.mm +++ b/platform/darwin/test/MGLExpressionTests.mm @@ -179,6 +179,13 @@ using namespace std::string_literals; NSMutableDictionary *context = [@{@"lineProgress": @1} mutableCopy]; XCTAssertEqualObjects([expression expressionValueWithObject:nil context:context], @1); } + { + NSExpression *expression = [NSExpression expressionForVariable:@"featureAccumulated"]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"accumulated"]); + XCTAssertEqualObjects([NSExpression expressionWithFormat:@"$featureAccumulated"].mgl_jsonExpressionObject, @[@"accumulated"]); + XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:@[@"accumulated"]], expression); + } + { NSExpression *expression = [NSExpression expressionForVariable:@"geometryType"]; XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, @[@"geometry-type"]); @@ -380,6 +387,26 @@ using namespace std::string_literals; XCTAssertEqualObjects([NSExpression expressionWithFormat:@"1 + 1"].mgl_jsonExpressionObject, jsonExpression); XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); } + { + NSExpression *testExpression = [NSExpression expressionWithFormat:@"sum:({1, 1, 2})"]; + NSExpression *expression = [NSExpression expressionForFunction:@"sum:" arguments:@[[NSExpression expressionForAggregate:@[MGLConstantExpression(@1), MGLConstantExpression(@1), MGLConstantExpression(@2)]]]]; + + NSArray *jsonExpression = @[@"+", @1, @1, @2]; + + XCTAssertEqualObjects(testExpression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + XCTAssertEqualObjects(expression, testExpression); + } + { + NSExpression *expression = [NSExpression expressionForFunction:@"sum:" arguments:@[MGLConstantExpression(@1), MGLConstantExpression(@1), MGLConstantExpression(@2)]]; + NSArray *jsonExpression = @[@"+", @1, @1, @2]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + + // - [NSExpression expressionWithMGLJSONObject:] creates an expression with an aggregate expression as an argument. This is not equal to an expression with an array of expressions as an argument. For testing purposes, we will compare their operands and arrays of expressions. + NSExpression *aggregateExpression = [NSExpression expressionWithMGLJSONObject:jsonExpression]; + XCTAssertEqualObjects(aggregateExpression.operand, expression.operand); + XCTAssertEqualObjects(aggregateExpression.arguments.firstObject.collection, expression.arguments); + } { NSArray *threeArguments = @[MGLConstantExpression(@1), MGLConstantExpression(@1), MGLConstantExpression(@1)]; NSExpression *expression = [NSExpression expressionForFunction:@"add:to:" arguments:threeArguments]; @@ -417,6 +444,24 @@ using namespace std::string_literals; // NSExpression lacks a shorthand operator for modulus. XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression); } + { + NSExpression *expression = [NSExpression expressionForFunction:@"max:" arguments:arguments]; + NSArray *jsonExpression = @[@"max", @1, @1]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + + NSExpression *aggregateExpression = [NSExpression expressionWithMGLJSONObject:jsonExpression]; + XCTAssertEqualObjects(aggregateExpression.operand, expression.operand); + XCTAssertEqualObjects(aggregateExpression.arguments.firstObject.collection, expression.arguments); + } + { + NSExpression *expression = [NSExpression expressionForFunction:@"min:" arguments:arguments]; + NSArray *jsonExpression = @[@"min", @1, @1]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + + NSExpression *aggregateExpression = [NSExpression expressionWithMGLJSONObject:jsonExpression]; + XCTAssertEqualObjects(aggregateExpression.operand, expression.operand); + XCTAssertEqualObjects(aggregateExpression.arguments.firstObject.collection, expression.arguments); + } { NSExpression *expression = [NSExpression expressionForFunction:@"ceiling:" arguments:@[MGLConstantExpression(@1.5)]]; NSArray *jsonExpression = @[@"ceil", @1.5]; @@ -621,6 +666,16 @@ using namespace std::string_literals; XCTAssertEqualObjects([aftermarketExpression expressionValueWithObject:nil context:nil], @"OldMacDonald"); XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], aftermarketExpression); } + { + NSExpression *expression = [NSExpression expressionForFunction:@"mgl_join:" arguments:@[@"Old", @"MacDonald"]]; + NSExpression *aftermarketExpression = [NSExpression expressionWithFormat:@"mgl_join({'Old', 'MacDonald'})"]; + NSArray *jsonExpression = @[@"concat", @"Old", @"MacDonald"]; + XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression); + + XCTAssertEqualObjects(aftermarketExpression.mgl_jsonExpressionObject, expression.mgl_jsonExpressionObject); + NSExpression *aggregateExpression = [NSExpression expressionWithMGLJSONObject:jsonExpression]; + XCTAssertEqualObjects(aggregateExpression.operand, expression.operand); + } { NSExpression *expression = [NSExpression expressionForFunction:@"uppercase:" arguments:arguments]; NSArray *jsonExpression = @[@"upcase", @"MacDonald"]; diff --git a/platform/darwin/test/MGLShapeSourceTests.mm b/platform/darwin/test/MGLShapeSourceTests.mm index 3459fb1733..3bf3ef04bd 100644 --- a/platform/darwin/test/MGLShapeSourceTests.mm +++ b/platform/darwin/test/MGLShapeSourceTests.mm @@ -13,8 +13,12 @@ @implementation MGLShapeSourceTests - (void)testGeoJSONOptionsFromDictionary { + NSExpression *reduceExpression = [NSExpression expressionForFunction:@"sum:" arguments:@[[NSExpression expressionForKeyPath:@"featureAccumulated"], [NSExpression expressionForKeyPath:@"sumValue"]]]; + NSExpression *mapExpression = [NSExpression expressionForKeyPath:@"mag"]; + NSArray *clusterPropertyArray = @[reduceExpression, mapExpression]; NSDictionary *options = @{MGLShapeSourceOptionClustered: @YES, MGLShapeSourceOptionClusterRadius: @42, + MGLShapeSourceOptionClusterProperties: @{@"sumValue": clusterPropertyArray}, MGLShapeSourceOptionMaximumZoomLevelForClustering: @98, MGLShapeSourceOptionMaximumZoomLevel: @99, MGLShapeSourceOptionBuffer: @1976, @@ -29,6 +33,7 @@ XCTAssertEqual(mbglOptions.buffer, 1976); XCTAssertEqual(mbglOptions.tolerance, 0.42); XCTAssertTrue(mbglOptions.lineMetrics); + XCTAssertTrue(!mbglOptions.clusterProperties.empty()); options = @{MGLShapeSourceOptionClustered: @"number 1"}; XCTAssertThrows(MGLGeoJSONOptionsFromDictionary(options)); diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 5a7235b25a..03ed8cdc46 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -14,6 +14,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Improved rendering performance for the styles with multiple sources ([#15756](https://github.com/mapbox/mapbox-gl-native/pull/15756)) +### Styles and rendering + +* Added an `MGLShapeSourceOptionClusterProperties` option that allows styling individual clusters based on aggregated feature data. ([#15515](https://github.com/mapbox/mapbox-gl-native/pull/15515)) + ### Other changes * Added `-[MGLMapSnapshotOverlay coordinateForPoint:]` and `-[MGLMapSnapshotOverlay pointForCoordinate:]` to convert between context and map coordinates, mirroring those of `MGLMapSnapshot`. ([#15746](https://github.com/mapbox/mapbox-gl-native/pull/15746)) diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index c3cb942709..8067b1ab1d 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -99,6 +99,7 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) Feature feature; clusterOptions.map = [&](const PropertyMap& properties) -> PropertyMap { PropertyMap ret{}; + if (properties.empty()) return ret; for (const auto& p : options.clusterProperties) { feature.properties = properties; ret[p.first] = evaluateFeature(feature, p.second.first); -- cgit v1.2.1 From 8206ce0e024a082f6979ce66f65909cb451e9d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 14 Oct 2019 14:38:17 +0200 Subject: [core] map image type to string until we have a dedicated implementation --- platform/android/scripts/generate-style-code.js | 6 ++++++ platform/darwin/scripts/generate-style-code.js | 9 +++++++++ scripts/generate-style-code.js | 3 +++ 3 files changed, 18 insertions(+) diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index fa814f89af..83fb5c116e 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -72,6 +72,7 @@ global.propertyType = function propertyType(property) { case 'formatted': return 'Formatted'; case 'string': + case 'image': // TODO: replace once we implement image expressions return 'String'; case 'enum': return 'String'; @@ -93,6 +94,7 @@ global.propertyJavaType = function propertyType(property) { case 'formatted': return 'Formatted'; case 'string': + case 'image': // TODO: replace once we implement image expressions return 'String'; case 'enum': return 'String'; @@ -141,6 +143,7 @@ global.propertyNativeType = function (property) { return 'float'; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return 'std::string'; case 'enum': if(property['light-property']){ @@ -177,6 +180,7 @@ global.defaultExpressionJava = function(property) { case 'formatted': return 'format'; case 'string': + case 'image': // TODO: replace once we implement image expressions return "string"; case 'enum': return "string"; @@ -203,6 +207,7 @@ global.defaultValueJava = function(property) { case 'formatted': return 'new Formatted(new FormattedSection("default"))' case 'string': + case 'image': // TODO: replace once we implement image expressions return '"' + property['default'] + '"'; case 'enum': return snakeCaseUpper(property.name) + "_" + snakeCaseUpper(Object.keys(property.values)[0]); @@ -335,6 +340,7 @@ global.evaluatedType = function (property) { return 'float'; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return 'std::string'; case 'enum': return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`; diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 38066c9f43..75dbdf367c 100755 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -159,6 +159,7 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) { `@"'${_.startCase(propertyName)}'"` : `@"${_.startCase(propertyName)}"`; case 'string': + case 'image': // TODO: replace once we implement image expressions return `@"'${_.startCase(propertyName)}'"`; case 'enum': return `@"'${_.last(_.keys(property.values))}'"`; @@ -208,6 +209,7 @@ global.mbglTestValue = function (property, layerType) { return '1.0'; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return `"${_.startCase(propertyName)}"`; case 'enum': { let type = camelize(originalPropertyName(property)); @@ -294,6 +296,7 @@ global.testHelperMessage = function (property, layerType, isFunction) { return 'testNumber' + fnSuffix; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return 'testString' + fnSuffix; case 'enum': let objCType = global.objCType(layerType, property.name); @@ -474,6 +477,7 @@ global.describeType = function (property) { return 'numeric'; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return 'string'; case 'enum': return '`MGL' + camelize(property.name) + '`'; @@ -522,6 +526,7 @@ global.describeValue = function (value, property, layerType) { return 'the float ' + '`' + formatNumber(value) + '`'; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions if (value === '') { return 'the empty string'; } @@ -608,6 +613,7 @@ global.propertyType = function (property) { return 'NSNumber *'; case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return 'NSString *'; case 'enum': return 'NSValue *'; @@ -640,6 +646,7 @@ global.isInterpolatable = function (property) { return type !== 'boolean' && type !== 'enum' && type !== 'string' && + type !== 'image' && type !== 'formatted'; }; @@ -653,6 +660,7 @@ global.valueTransformerArguments = function (property) { case 'formatted': return ['mbgl::style::expression::Formatted', objCType]; case 'string': + case 'image': // TODO: replace once we implement image expressions return ['std::string', objCType]; case 'enum': return [mbglType(property), 'NSValue *', mbglType(property), `MGL${camelize(property.name)}`]; @@ -692,6 +700,7 @@ global.mbglType = function(property) { case 'formatted': return 'mbgl::style::expression::Formatted'; case 'string': + case 'image': // TODO: replace once we implement image expressions return 'std::string'; case 'enum': { let type = camelize(originalPropertyName(property)); diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 1f26e6fd86..0aedba909b 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -36,6 +36,7 @@ global.expressionType = function (property) { case 'enum': return 'NumberType'; case 'string': + case 'image': // TODO: replace once we implement image expressions return 'StringType'; case 'color': return `ColorType`; @@ -68,6 +69,7 @@ global.evaluatedType = function (property) { case 'formatted': return 'expression::Formatted'; case 'string': + case 'image': // TODO: replace once we implement image expressions return 'std::string'; case 'enum': return (isLightProperty(property) ? 'Light' : '') + `${camelize(property.name)}Type`; @@ -166,6 +168,7 @@ global.defaultValue = function (property) { } case 'formatted': case 'string': + case 'image': // TODO: replace once we implement image expressions return JSON.stringify(property.default || ""); case 'enum': if (property.default === undefined) { -- cgit v1.2.1 From 9cac122c5cf6404b9c8cdb52f130f7386a273241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 14 Oct 2019 15:15:54 +0200 Subject: [core] map image type to string until we have a dedicated implementation --- expression-test/expression_test_parser.cpp | 3 +- platform/node/test/ignores.json | 4 ++ src/mbgl/style/expression/assertion.cpp | 6 +-- src/mbgl/style/expression/parsing_context.cpp | 66 ++++++++++++++------------- src/mbgl/text/shaping.cpp | 2 +- 5 files changed, 44 insertions(+), 37 deletions(-) diff --git a/expression-test/expression_test_parser.cpp b/expression-test/expression_test_parser.cpp index 546a96b3e0..3b40eeb3b0 100644 --- a/expression-test/expression_test_parser.cpp +++ b/expression-test/expression_test_parser.cpp @@ -104,7 +104,8 @@ optional toValue(const JSValue& jsvalue) { style::expression::type::Type stringToType(const std::string& type) { using namespace style::expression; - if (type == "string"s || type == "number-format"s) { + if (type == "string"s || type == "number-format"s || + type == "image"s) { // TODO: replace once we implement image expressions return type::String; } else if (type == "number"s) { return type::Number; diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json index 8da2905dbb..289f38be38 100644 --- a/platform/node/test/ignores.json +++ b/platform/node/test/ignores.json @@ -16,6 +16,10 @@ "expression-tests/legacy/interval/composite": "https://github.com/mapbox/mapbox-gl-native/issues/12747", "expression-tests/legacy/interval/composite-default": "https://github.com/mapbox/mapbox-gl-native/issues/12747", "expression-tests/legacy/interval/tokens-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/12747", + "expression-tests/image/basic": "https://github.com/mapbox/mapbox-gl-native/issues/15800", + "expression-tests/image/compound": "https://github.com/mapbox/mapbox-gl-native/issues/15800", + "expression-tests/image/coalesce": "https://github.com/mapbox/mapbox-gl-native/issues/15800", + "expression-tests/image/implicit-assert": "https://github.com/mapbox/mapbox-gl-native/issues/15800", "query-tests/geometry/multilinestring": "needs investigation", "query-tests/geometry/multipolygon": "needs investigation", "query-tests/geometry/polygon": "needs investigation", diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 8e5a8b555d..17f8925511 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -16,12 +16,12 @@ Assertion::Assertion(type::Type type_, std::vector> } ParseResult Assertion::parse(const Convertible& value, ParsingContext& ctx) { - static std::unordered_map types { + static std::unordered_map types{ {"string", type::String}, + {"image", type::String}, // TODO: replace once we implement image expressions {"number", type::Number}, {"boolean", type::Boolean}, - {"object", type::Object} - }; + {"object", type::Object}}; std::size_t length = arrayLength(value); diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index 6ce3a9bfaa..699190608b 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -100,38 +100,40 @@ ParseResult ParsingContext::parse(const Convertible& value, std::size_t index_, } using ParseFunction = ParseResult (*)(const conversion::Convertible&, ParsingContext&); -MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = mapbox::eternal::hash_map({ - {"==", parseComparison}, - {"!=", parseComparison}, - {">", parseComparison}, - {"<", parseComparison}, - {">=", parseComparison}, - {"<=", parseComparison}, - {"all", All::parse}, - {"any", Any::parse}, - {"array", Assertion::parse}, - {"at", At::parse}, - {"boolean", Assertion::parse}, - {"case", Case::parse}, - {"coalesce", Coalesce::parse}, - {"collator", CollatorExpression::parse}, - {"format", FormatExpression::parse}, - {"interpolate", parseInterpolate}, - {"length", Length::parse}, - {"let", Let::parse}, - {"literal", Literal::parse}, - {"match", parseMatch}, - {"number", Assertion::parse}, - {"number-format", NumberFormat::parse}, - {"object", Assertion::parse}, - {"step", Step::parse}, - {"string", Assertion::parse}, - {"to-boolean", Coercion::parse}, - {"to-color", Coercion::parse}, - {"to-number", Coercion::parse}, - {"to-string", Coercion::parse}, - {"var", Var::parse}, -}); +MAPBOX_ETERNAL_CONSTEXPR const auto expressionRegistry = + mapbox::eternal::hash_map({ + {"==", parseComparison}, + {"!=", parseComparison}, + {">", parseComparison}, + {"<", parseComparison}, + {">=", parseComparison}, + {"<=", parseComparison}, + {"all", All::parse}, + {"any", Any::parse}, + {"array", Assertion::parse}, + {"at", At::parse}, + {"boolean", Assertion::parse}, + {"case", Case::parse}, + {"coalesce", Coalesce::parse}, + {"collator", CollatorExpression::parse}, + {"format", FormatExpression::parse}, + {"image", Assertion::parse}, // TODO: replace once we implement image expressions + {"interpolate", parseInterpolate}, + {"length", Length::parse}, + {"let", Let::parse}, + {"literal", Literal::parse}, + {"match", parseMatch}, + {"number", Assertion::parse}, + {"number-format", NumberFormat::parse}, + {"object", Assertion::parse}, + {"step", Step::parse}, + {"string", Assertion::parse}, + {"to-boolean", Coercion::parse}, + {"to-color", Coercion::parse}, + {"to-number", Coercion::parse}, + {"to-string", Coercion::parse}, + {"var", Var::parse}, + }); bool isExpression(const std::string& name) { return expressionRegistry.contains(name.c_str()); diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index d6d9a3d34e..4ae9d0cf20 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -32,7 +32,7 @@ AnchorAlignment AnchorAlignment::getAnchorAlignment(style::SymbolAnchorType anch result.horizontalAlign = 0.0f; break; default: - break; + break; } switch (anchor) { -- cgit v1.2.1 From 2187980a871cc22f59c1078a949e42db0ab7c1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 14 Oct 2019 15:16:14 +0200 Subject: [core] fix icon-text-fit This fixes rendering by account for the 1px texture padding around icons that were stretched with icon-text-fit. We've added the 1px padding before, but didn't scale it accordingly when we are resizing the icon when it is stretched to fit the text. Adjusts the code to match the logic in GL JS. --- mapbox-gl-js | 2 +- platform/node/test/ignores.json | 3 + src/mbgl/layout/symbol_layout.cpp | 19 +-- src/mbgl/text/quads.cpp | 28 +++- src/mbgl/text/shaping.cpp | 62 +++---- src/mbgl/text/shaping.hpp | 8 +- test/text/quads.test.cpp | 329 ++++++++++++++++---------------------- 7 files changed, 215 insertions(+), 236 deletions(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index 7ea73ed381..2dbbf63490 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 7ea73ed381a81c3ff7e48b523b25d50793baf1f5 +Subproject commit 2dbbf634906dc1b02b48cb740dadb6de16348475 diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json index 289f38be38..51decb351c 100644 --- a/platform/node/test/ignores.json +++ b/platform/node/test/ignores.json @@ -76,6 +76,9 @@ "render-tests/fill-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008", "render-tests/line-sort-key/literal": "https://github.com/mapbox/mapbox-gl-native/issues/15008", "render-tests/regressions/mapbox-gl-js#8817": "skip - https://github.com/mapbox/mapbox-gl-native/issues/15737", + "render-tests/text-max-width/zero-width-point-placement": "https://github.com/mapbox/mapbox-gl-native/issues/15648", + "render-tests/icon-image/image-expression": "https://github.com/mapbox/mapbox-gl-native/issues/15800", + "render-tests/icon-text-fit/text-variable-anchor-overlap": "https://github.com/mapbox/mapbox-gl-native/issues/15809", "query-tests/fill-extrusion/base-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139", "query-tests/fill-extrusion/box-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139", "query-tests/fill-extrusion/side-in": "https://github.com/mapbox/mapbox-gl-native/issues/13139", diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 81d1d9a5b6..d0227c36c5 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -121,7 +121,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, allowVerticalPlacement = allowVerticalPlacement || placementMode == style::TextWritingModeType::Vertical; return !seen.insert(placementMode).second; }); - modes.erase(end, modes.end()); + modes.erase(end, modes.end()); placementModes = std::move(modes); } @@ -525,21 +525,22 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const float textRepeatDistance = symbolSpacing / 2; const auto evaluatedLayoutProperties = layout->evaluate(zoom, feature); IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size()); - const bool hasIconTextFit = evaluatedLayoutProperties.get() != IconTextFitType::None; + const auto iconTextFit = evaluatedLayoutProperties.get(); // Adjust shaped icon size when icon-text-fit is used. optional verticallyShapedIcon; - if (shapedIcon && hasIconTextFit) { + if (shapedIcon && iconTextFit != IconTextFitType::None) { // Create vertically shaped icon for vertical writing mode if needed. if (allowVerticalPlacement && shapedTextOrientations.vertical) { verticallyShapedIcon = shapedIcon; - verticallyShapedIcon->fitIconToText(evaluatedLayoutProperties, - shapedTextOrientations.vertical, - layoutTextSize); + verticallyShapedIcon->fitIconToText( + shapedTextOrientations.vertical, iconTextFit, layout->get(), iconOffset, fontScale); + } + const auto shapedText = getDefaultHorizontalShaping(shapedTextOrientations); + if (shapedText) { + shapedIcon->fitIconToText( + shapedText, iconTextFit, layout->get(), iconOffset, fontScale); } - shapedIcon->fitIconToText(evaluatedLayoutProperties, - getDefaultHorizontalShaping(shapedTextOrientations), - layoutTextSize); } auto addSymbolInstance = [&] (Anchor& anchor, std::shared_ptr sharedData) { diff --git a/src/mbgl/text/quads.cpp b/src/mbgl/text/quads.cpp index 281c5d99de..a94bfee336 100644 --- a/src/mbgl/text/quads.cpp +++ b/src/mbgl/text/quads.cpp @@ -20,12 +20,28 @@ SymbolQuad getIconQuad(const PositionedIcon& shapedIcon, // If you have a 10px icon that isn't perfectly aligned to the pixel grid it will cover 11 actual // pixels. The quad needs to be padded to account for this, otherwise they'll look slightly clipped // on one edge in some cases. - const float border = 1.0; - - float top = shapedIcon.top() - border / image.pixelRatio; - float left = shapedIcon.left() - border / image.pixelRatio; - float bottom = shapedIcon.bottom() + border / image.pixelRatio; - float right = shapedIcon.right() + border / image.pixelRatio; + constexpr const float border = 1.0f; + + // Expand the box to respect the 1 pixel border in the atlas image. We're using `image.paddedRect - border` + // instead of image.displaySize because we only pad with one pixel for retina images as well, and the + // displaySize uses the logical dimensions, not the physical pixel dimensions. + // Unlike the JavaScript version, we're _not_ including the padding in the texture rect, so the + // logic "dimension * padded / non-padded - dimension" is swapped. + const float iconWidth = shapedIcon.right() - shapedIcon.left(); + const float expandX = (iconWidth * (static_cast(image.textureRect.w) + 2.0f * border) / + static_cast(image.textureRect.w) - + iconWidth) / + 2.0f; + const float left = shapedIcon.left() - expandX; + const float right = shapedIcon.right() + expandX; + + const float iconHeight = shapedIcon.bottom() - shapedIcon.top(); + const float expandY = (iconHeight * (static_cast(image.textureRect.h) + 2.0f * border) / + static_cast(image.textureRect.h) - + iconHeight) / + 2.0f; + const float top = shapedIcon.top() - expandY; + const float bottom = shapedIcon.bottom() + expandY; Point tl{left, top}; Point tr{right, top}; diff --git a/src/mbgl/text/shaping.cpp b/src/mbgl/text/shaping.cpp index 4ae9d0cf20..8eb885af5d 100644 --- a/src/mbgl/text/shaping.cpp +++ b/src/mbgl/text/shaping.cpp @@ -83,33 +83,41 @@ PositionedIcon PositionedIcon::shapeIcon(const ImagePosition& image, return PositionedIcon { image, top, bottom, left, right, iconRotation }; } -void PositionedIcon::fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout, - const Shaping& shapedText, - float layoutTextSize) { - using namespace style; - assert(layout.get() != IconTextFitType::None); - if (shapedText) { - auto iconWidth = _right - _left; - auto iconHeight = _bottom - _top; - auto size = layoutTextSize / 24.0f; - auto textLeft = shapedText.left * size; - auto textRight = shapedText.right * size; - auto textTop = shapedText.top * size; - auto textBottom = shapedText.bottom * size; - auto textWidth = textRight - textLeft; - auto textHeight = textBottom - textTop; - auto padT = layout.get()[0]; - auto padR = layout.get()[1]; - auto padB = layout.get()[2]; - auto padL = layout.get()[3]; - auto offsetY = layout.get() == IconTextFitType::Width ? (textHeight - iconHeight) * 0.5 : 0; - auto offsetX = layout.get() == IconTextFitType::Height ? (textWidth - iconWidth) * 0.5 : 0; - auto width = layout.get() == IconTextFitType::Width || layout.get() == IconTextFitType::Both ? textWidth : iconWidth; - auto height = layout.get() == IconTextFitType::Height || layout.get() == IconTextFitType::Both ? textHeight : iconHeight; - _left = textLeft + offsetX - padL; - _top = textTop + offsetY - padT; - _right = textLeft + offsetX + padR + width; - _bottom = textTop + offsetY + padB + height; +void PositionedIcon::fitIconToText(const Shaping& shapedText, + const style::IconTextFitType textFit, + const std::array& padding, + const std::array& iconOffset, + const float fontScale) { + assert(textFit != style::IconTextFitType::None); + assert(shapedText); + + // We don't respect the icon-anchor, because icon-text-fit is set. Instead, + // the icon will be centered on the text, then stretched in the given + // dimensions. + + const float textLeft = shapedText.left * fontScale; + const float textRight = shapedText.right * fontScale; + + if (textFit == style::IconTextFitType::Width || textFit == style::IconTextFitType::Both) { + // Stretched horizontally to the text width + _left = iconOffset[0] + textLeft - padding[3]; + _right = iconOffset[0] + textRight + padding[1]; + } else { + // Centered on the text + _left = iconOffset[0] + (textLeft + textRight - image().displaySize()[0]) / 2.0f; + _right = _left + image().displaySize()[0]; + } + + const float textTop = shapedText.top * fontScale; + const float textBottom = shapedText.bottom * fontScale; + if (textFit == style::IconTextFitType::Height || textFit == style::IconTextFitType::Both) { + // Stretched vertically to the text height + _top = iconOffset[1] + textTop - padding[0]; + _bottom = iconOffset[1] + textBottom + padding[2]; + } else { + // Centered on the text + _top = iconOffset[1] + (textTop + textBottom - image().displaySize()[1]) / 2.0f; + _bottom = _top + image().displaySize()[1]; } } diff --git a/src/mbgl/text/shaping.hpp b/src/mbgl/text/shaping.hpp index 28730e9db9..6ed1b5cb0e 100644 --- a/src/mbgl/text/shaping.hpp +++ b/src/mbgl/text/shaping.hpp @@ -45,9 +45,11 @@ public: // Updates shaped icon's bounds based on shaped text's bounds and provided // layout properties. - void fitIconToText(const style::SymbolLayoutProperties::Evaluated& layout, - const Shaping& shapedText, - float layoutTextSize); + void fitIconToText(const Shaping& shapedText, + const style::IconTextFitType textFit, + const std::array& padding, + const std::array& iconOffset, + const float fontScale); const ImagePosition& image() const { return _image; } float top() const { return _top; } diff --git a/test/text/quads.test.cpp b/test/text/quads.test.cpp index 7aaeb4870d..b04617a40b 100644 --- a/test/text/quads.test.cpp +++ b/test/text/quads.test.cpp @@ -36,10 +36,8 @@ TEST(getIconQuads, normal) { TEST(getIconQuads, style) { Anchor anchor(0.0, 0.0, 0.0, 0.5f, 0); - ImagePosition image = { - mapbox::Bin(-1, 20, 20, 0, 0, 0, 0), - style::Image::Impl("test", PremultipliedImage({1,1}), 1.0) - }; + const ImagePosition image = {mapbox::Bin(-1, 20, 20, 0, 0, 0, 0), + style::Image::Impl("test", PremultipliedImage({1, 1}), 1.0)}; GeometryCoordinates line; Shaping shapedText; @@ -51,235 +49,186 @@ TEST(getIconQuads, style) { // none { - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + + EXPECT_FLOAT_EQ(-18.5f, shapedIcon.top()); + EXPECT_FLOAT_EQ(-0.5f, shapedIcon.right()); + EXPECT_FLOAT_EQ(-0.5f, shapedIcon.bottom()); + EXPECT_FLOAT_EQ(-18.5f, shapedIcon.left()); + SymbolLayoutProperties::Evaluated layout; - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -19.5); - EXPECT_EQ(quad.tl.y, -19.5); - EXPECT_EQ(quad.tr.x, 0.5); - EXPECT_EQ(quad.tr.y, -19.5); - EXPECT_EQ(quad.bl.x, -19.5); - EXPECT_EQ(quad.bl.y, 0.5); - EXPECT_EQ(quad.br.x, 0.5); - EXPECT_EQ(quad.br.y, 0.5); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -19.5); + EXPECT_FLOAT_EQ(quad.tl.y, -19.5); + EXPECT_FLOAT_EQ(quad.tr.x, 0.5); + EXPECT_FLOAT_EQ(quad.tr.y, -19.5); + EXPECT_FLOAT_EQ(quad.bl.x, -19.5); + EXPECT_FLOAT_EQ(quad.bl.y, 0.5); + EXPECT_FLOAT_EQ(quad.br.x, 0.5); + EXPECT_FLOAT_EQ(quad.br.y, 0.5); } // width { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 24.0f; - layout.get() = IconTextFitType::Width; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 24.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -61); - EXPECT_EQ(quad.tl.y, 0); - EXPECT_EQ(quad.tr.x, 21); - EXPECT_EQ(quad.tr.y, 0); - EXPECT_EQ(quad.bl.x, -61); - EXPECT_EQ(quad.bl.y, 20); - EXPECT_EQ(quad.br.x, 21); - EXPECT_EQ(quad.br.y, 20); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Width, {{0, 0, 0, 0}}, {{0, 0}}, 24.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -64.4444427); + EXPECT_FLOAT_EQ(quad.tl.y, 0); + EXPECT_FLOAT_EQ(quad.tr.x, 24.4444427); + EXPECT_FLOAT_EQ(quad.tr.y, 0); + EXPECT_FLOAT_EQ(quad.bl.x, -64.4444427); + EXPECT_FLOAT_EQ(quad.bl.y, 20); + EXPECT_FLOAT_EQ(quad.br.x, 24.4444427); + EXPECT_FLOAT_EQ(quad.br.y, 20); } // width x textSize { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 12.0f; - layout.get() = IconTextFitType::Width; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -31); - EXPECT_EQ(quad.tl.y, -5); - EXPECT_EQ(quad.tr.x, 11); - EXPECT_EQ(quad.tr.y, -5); - EXPECT_EQ(quad.bl.x, -31); - EXPECT_EQ(quad.bl.y, 15); - EXPECT_EQ(quad.br.x, 11); - EXPECT_EQ(quad.br.y, 15); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Width, {{0, 0, 0, 0}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -32.2222214); + EXPECT_FLOAT_EQ(quad.tl.y, -5); + EXPECT_FLOAT_EQ(quad.tr.x, 12.2222214); + EXPECT_FLOAT_EQ(quad.tr.y, -5); + EXPECT_FLOAT_EQ(quad.bl.x, -32.2222214); + EXPECT_FLOAT_EQ(quad.bl.y, 15); + EXPECT_FLOAT_EQ(quad.br.x, 12.2222214); + EXPECT_FLOAT_EQ(quad.br.y, 15); } // width x textSize + padding { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 12.0f; - layout.get() = IconTextFitType::Width; - layout.get()[0] = 5.0f; - layout.get()[1] = 10.0f; - layout.get()[2] = 5.0f; - layout.get()[3] = 10.0f; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -41); - EXPECT_EQ(quad.tl.y, -10); - EXPECT_EQ(quad.tr.x, 21); - EXPECT_EQ(quad.tr.y, -10); - EXPECT_EQ(quad.bl.x, -41); - EXPECT_EQ(quad.bl.y, 20); - EXPECT_EQ(quad.br.x, 21); - EXPECT_EQ(quad.br.y, 20); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Width, {{5, 10, 5, 10}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -43.3333321); + EXPECT_FLOAT_EQ(quad.tl.y, -5); + EXPECT_FLOAT_EQ(quad.tr.x, 23.3333321); + EXPECT_FLOAT_EQ(quad.tr.y, -5); + EXPECT_FLOAT_EQ(quad.bl.x, -43.3333321); + EXPECT_FLOAT_EQ(quad.bl.y, 15); + EXPECT_FLOAT_EQ(quad.br.x, 23.3333321); + EXPECT_FLOAT_EQ(quad.br.y, 15); } // height { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 24.0f; - layout.get() = IconTextFitType::Height; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 24.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -30); - EXPECT_EQ(quad.tl.y, -11); - EXPECT_EQ(quad.tr.x, -10); - EXPECT_EQ(quad.tr.y, -11); - EXPECT_EQ(quad.bl.x, -30); - EXPECT_EQ(quad.bl.y, 31); - EXPECT_EQ(quad.br.x, -10); - EXPECT_EQ(quad.br.y, 31); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Height, {{0, 0, 0, 0}}, {{0, 0}}, 24.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -30); + EXPECT_FLOAT_EQ(quad.tl.y, -12.2222214); + EXPECT_FLOAT_EQ(quad.tr.x, -10); + EXPECT_FLOAT_EQ(quad.tr.y, -12.2222214); + EXPECT_FLOAT_EQ(quad.bl.x, -30); + EXPECT_FLOAT_EQ(quad.bl.y, 32.2222214); + EXPECT_FLOAT_EQ(quad.br.x, -10); + EXPECT_FLOAT_EQ(quad.br.y, 32.2222214); } // height x textSize { SymbolLayoutProperties::Evaluated layout; - layout.get() = 12.0f; - layout.get() = IconTextFitType::Height; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -20); - EXPECT_EQ(quad.tl.y, -6); - EXPECT_EQ(quad.tr.x, 0); - EXPECT_EQ(quad.tr.y, -6); - EXPECT_EQ(quad.bl.x, -20); - EXPECT_EQ(quad.bl.y, 16); - EXPECT_EQ(quad.br.x, 0); - EXPECT_EQ(quad.br.y, 16); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Height, {{0, 0, 0, 0}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -20); + EXPECT_FLOAT_EQ(quad.tl.y, -6.11111069); + EXPECT_FLOAT_EQ(quad.tr.x, 0); + EXPECT_FLOAT_EQ(quad.tr.y, -6.11111069); + EXPECT_FLOAT_EQ(quad.bl.x, -20); + EXPECT_FLOAT_EQ(quad.bl.y, 16.1111107); + EXPECT_FLOAT_EQ(quad.br.x, 0); + EXPECT_FLOAT_EQ(quad.br.y, 16.1111107); } // height x textSize + padding { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 12.0f; - layout.get() = IconTextFitType::Height; - layout.get()[0] = 5.0f; - layout.get()[1] = 10.0f; - layout.get()[2] = 5.0f; - layout.get()[3] = 10.0f; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -30); - EXPECT_EQ(quad.tl.y, -11); - EXPECT_EQ(quad.tr.x, 10); - EXPECT_EQ(quad.tr.y, -11); - EXPECT_EQ(quad.bl.x, -30); - EXPECT_EQ(quad.bl.y, 21); - EXPECT_EQ(quad.br.x, 10); - EXPECT_EQ(quad.br.y, 21); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Height, {{5, 10, 5, 20}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -20); + EXPECT_FLOAT_EQ(quad.tl.y, -11.666666); + EXPECT_FLOAT_EQ(quad.tr.x, 0); + EXPECT_FLOAT_EQ(quad.tr.y, -11.666666); + EXPECT_FLOAT_EQ(quad.bl.x, -20); + EXPECT_FLOAT_EQ(quad.bl.y, 21.666666); + EXPECT_FLOAT_EQ(quad.br.x, 0); + EXPECT_FLOAT_EQ(quad.br.y, 21.666666); } // both { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 24.0f; - layout.get() = IconTextFitType::Both; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 24.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -61); - EXPECT_EQ(quad.tl.y, -11); - EXPECT_EQ(quad.tr.x, 21); - EXPECT_EQ(quad.tr.y, -11); - EXPECT_EQ(quad.bl.x, -61); - EXPECT_EQ(quad.bl.y, 31); - EXPECT_EQ(quad.br.x, 21); - EXPECT_EQ(quad.br.y, 31); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Both, {{0, 0, 0, 0}}, {{0, 0}}, 24.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -64.4444427); + EXPECT_FLOAT_EQ(quad.tl.y, -12.2222214); + EXPECT_FLOAT_EQ(quad.tr.x, 24.4444427); + EXPECT_FLOAT_EQ(quad.tr.y, -12.2222214); + EXPECT_FLOAT_EQ(quad.bl.x, -64.4444427); + EXPECT_FLOAT_EQ(quad.bl.y, 32.2222214); + EXPECT_FLOAT_EQ(quad.br.x, 24.4444427); + EXPECT_FLOAT_EQ(quad.br.y, 32.2222214); } // both x textSize { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 12.0f; - layout.get() = IconTextFitType::Both; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -31); - EXPECT_EQ(quad.tl.y, -6); - EXPECT_EQ(quad.tr.x, 11); - EXPECT_EQ(quad.tr.y, -6); - EXPECT_EQ(quad.bl.x, -31); - EXPECT_EQ(quad.bl.y, 16); - EXPECT_EQ(quad.br.x, 11); - EXPECT_EQ(quad.br.y, 16); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Both, {{0, 0, 0, 0}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -32.2222214); + EXPECT_FLOAT_EQ(quad.tl.y, -6.11111069); + EXPECT_FLOAT_EQ(quad.tr.x, 12.2222214); + EXPECT_FLOAT_EQ(quad.tr.y, -6.11111069); + EXPECT_FLOAT_EQ(quad.bl.x, -32.2222214); + EXPECT_FLOAT_EQ(quad.bl.y, 16.1111107); + EXPECT_FLOAT_EQ(quad.br.x, 12.2222214); + EXPECT_FLOAT_EQ(quad.br.y, 16.1111107); } // both x textSize + padding { - SymbolLayoutProperties::Evaluated layout; - layout.get() = 12.0f; - layout.get() = IconTextFitType::Both; - layout.get()[0] = 5.0f; - layout.get()[1] = 10.0f; - layout.get()[2] = 5.0f; - layout.get()[3] = 10.0f; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -41); - EXPECT_EQ(quad.tl.y, -11); - EXPECT_EQ(quad.tr.x, 21); - EXPECT_EQ(quad.tr.y, -11); - EXPECT_EQ(quad.bl.x, -41); - EXPECT_EQ(quad.bl.y, 21); - EXPECT_EQ(quad.br.x, 21); - EXPECT_EQ(quad.br.y, 21); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Both, {{5, 10, 5, 10}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -43.3333321); + EXPECT_FLOAT_EQ(quad.tl.y, -11.666666); + EXPECT_FLOAT_EQ(quad.tr.x, 23.3333321); + EXPECT_FLOAT_EQ(quad.tr.y, -11.666666); + EXPECT_FLOAT_EQ(quad.bl.x, -43.3333321); + EXPECT_FLOAT_EQ(quad.bl.y, 21.666666); + EXPECT_FLOAT_EQ(quad.br.x, 23.3333321); + EXPECT_FLOAT_EQ(quad.br.y, 21.666666); } // both x textSize + padding t/r/b/l { SymbolLayoutProperties::Evaluated layout; layout.get() = 12.0f; - layout.get() = IconTextFitType::Both; - layout.get()[0] = 0.0f; - layout.get()[1] = 5.0f; - layout.get()[2] = 10.0f; - layout.get()[3] = 15.0f; - auto shapedIcon = PositionedIcon::shapeIcon(image, {{ -9.5f, -9.5f }}, SymbolAnchorType::Center, 0); - shapedIcon.fitIconToText(layout, shapedText, 12.0f); - SymbolQuad quad = - getIconQuad(shapedIcon, WritingModeType::Horizontal); - - EXPECT_EQ(quad.tl.x, -46); - EXPECT_EQ(quad.tl.y, -6); - EXPECT_EQ(quad.tr.x, 16); - EXPECT_EQ(quad.tr.y, -6); - EXPECT_EQ(quad.bl.x, -46); - EXPECT_EQ(quad.bl.y, 26); - EXPECT_EQ(quad.br.x, 16); - EXPECT_EQ(quad.br.y, 26); + auto shapedIcon = PositionedIcon::shapeIcon(image, {{-9.5f, -9.5f}}, SymbolAnchorType::Center, 0); + shapedIcon.fitIconToText(shapedText, IconTextFitType::Both, {{0, 5, 10, 15}}, {{0, 0}}, 12.0f / 24.0f); + SymbolQuad quad = getIconQuad(shapedIcon, WritingModeType::Horizontal); + + EXPECT_FLOAT_EQ(quad.tl.x, -48.3333321); + EXPECT_FLOAT_EQ(quad.tl.y, -6.66666603); + EXPECT_FLOAT_EQ(quad.tr.x, 18.3333321); + EXPECT_FLOAT_EQ(quad.tr.y, -6.66666603); + EXPECT_FLOAT_EQ(quad.bl.x, -48.3333321); + EXPECT_FLOAT_EQ(quad.bl.y, 26.666666); + EXPECT_FLOAT_EQ(quad.br.x, 18.3333321); + EXPECT_FLOAT_EQ(quad.br.y, 26.666666); } } - -- cgit v1.2.1 From 8b3a222c81abdfacddd6019135c1f655273ecaa5 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Sun, 13 Oct 2019 17:49:49 +0300 Subject: [render-test] Add tolerance to file-size tests --- render-test/metadata.hpp | 10 +++++++++- render-test/parser.cpp | 2 +- render-test/runner.cpp | 9 ++++++--- render-test/tests/file-size/fail-file-doesnt-match/style.json | 4 ++-- render-test/tests/file-size/fail-file-not-found/style.json | 4 ++-- render-test/tests/file-size/fail-size-is-over/style.json | 4 ++-- render-test/tests/file-size/fail-size-is-under/style.json | 4 ++-- render-test/tests/file-size/pass-size-is-same/metrics.json | 2 +- render-test/tests/file-size/pass-size-is-same/style.json | 4 ++-- 9 files changed, 27 insertions(+), 16 deletions(-) diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index e881bce208..bd26e6a7ba 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -31,12 +31,20 @@ struct TestPaths { } }; +inline std::tuple checkValue(float expected, float actual, float tolerance) { + float delta = expected * tolerance; + assert(delta >= 0.0f); + return std::make_tuple(std::abs(expected - actual) <= delta, delta); +} + struct FileSizeProbe { FileSizeProbe() = default; - FileSizeProbe(std::string path_, uintmax_t size_) : path(std::move(path_)), size(size_) {} + FileSizeProbe(std::string path_, uintmax_t size_, float tolerance_) + : path(std::move(path_)), size(size_), tolerance(tolerance_) {} std::string path; uintmax_t size; + float tolerance; }; struct MemoryProbe { diff --git a/render-test/parser.cpp b/render-test/parser.cpp index cbbc43293a..f4e54493eb 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -478,7 +478,7 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { result.fileSize.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(mark)), - std::forward_as_tuple(std::move(filePath), probeValue[2].GetUint64())); + std::forward_as_tuple(std::move(filePath), probeValue[2].GetUint64(), 0.f)); } } diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 103a14a079..3594c9488b 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -258,7 +258,8 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, return false; } - if (actual->second.size != expected.second.size) { + auto result = checkValue(expected.second.size, actual->second.size, actual->second.tolerance); + if (!std::get(result)) { std::stringstream ss; ss << "File size does not match at probe \"" << expected.first << "\": " << actual->second.size << ", expected is " << expected.second.size << "."; @@ -574,14 +575,16 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } } else if (operationArray[0].GetString() == fileSizeProbeOp) { // probeFileSize - assert(operationArray.Size() >= 3u); + assert(operationArray.Size() >= 4u); assert(operationArray[1].IsString()); assert(operationArray[2].IsString()); + assert(operationArray[3].IsNumber()); std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength()); std::string path = std::string(operationArray[2].GetString(), operationArray[2].GetStringLength()); assert(!path.empty()); + float tolerance = operationArray[3].GetDouble(); mbgl::filesystem::path filePath(path); if (!filePath.is_absolute()) { @@ -592,7 +595,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { auto size = mbgl::filesystem::file_size(filePath); metadata.metrics.fileSize.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(mark)), - std::forward_as_tuple(std::move(path), size)); + std::forward_as_tuple(std::move(path), size, tolerance)); } else { metadata.errorMessage = std::string("File not found: ") + path; return false; diff --git a/render-test/tests/file-size/fail-file-doesnt-match/style.json b/render-test/tests/file-size/fail-file-doesnt-match/style.json index a3267fcf5e..839a8d4a12 100644 --- a/render-test/tests/file-size/fail-file-doesnt-match/style.json +++ b/render-test/tests/file-size/fail-file-doesnt-match/style.json @@ -3,8 +3,8 @@ "metadata": { "test": { "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] + ["probeFileSize", "style", "style.json", 0], + ["probeFileSize", "image", "expected.png", 0] ], "width": 64, "height": 64 diff --git a/render-test/tests/file-size/fail-file-not-found/style.json b/render-test/tests/file-size/fail-file-not-found/style.json index 17dbd1e3d7..74054e1f40 100644 --- a/render-test/tests/file-size/fail-file-not-found/style.json +++ b/render-test/tests/file-size/fail-file-not-found/style.json @@ -3,8 +3,8 @@ "metadata": { "test": { "operations": [ - ["probeFileSize", "style", "style.aaaa"], - ["probeFileSize", "image", "expected.bbb"] + ["probeFileSize", "style", "style.aaaa", 0], + ["probeFileSize", "image", "expected.bbb", 0] ], "width": 64, "height": 64 diff --git a/render-test/tests/file-size/fail-size-is-over/style.json b/render-test/tests/file-size/fail-size-is-over/style.json index a3267fcf5e..839a8d4a12 100644 --- a/render-test/tests/file-size/fail-size-is-over/style.json +++ b/render-test/tests/file-size/fail-size-is-over/style.json @@ -3,8 +3,8 @@ "metadata": { "test": { "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] + ["probeFileSize", "style", "style.json", 0], + ["probeFileSize", "image", "expected.png", 0] ], "width": 64, "height": 64 diff --git a/render-test/tests/file-size/fail-size-is-under/style.json b/render-test/tests/file-size/fail-size-is-under/style.json index a3267fcf5e..839a8d4a12 100644 --- a/render-test/tests/file-size/fail-size-is-under/style.json +++ b/render-test/tests/file-size/fail-size-is-under/style.json @@ -3,8 +3,8 @@ "metadata": { "test": { "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] + ["probeFileSize", "style", "style.json", 0], + ["probeFileSize", "image", "expected.png", 0] ], "width": 64, "height": 64 diff --git a/render-test/tests/file-size/pass-size-is-same/metrics.json b/render-test/tests/file-size/pass-size-is-same/metrics.json index b98328f72e..3d560bd610 100644 --- a/render-test/tests/file-size/pass-size-is-same/metrics.json +++ b/render-test/tests/file-size/pass-size-is-same/metrics.json @@ -8,7 +8,7 @@ [ "style", "style.json", - 510 + 516 ] ] } \ No newline at end of file diff --git a/render-test/tests/file-size/pass-size-is-same/style.json b/render-test/tests/file-size/pass-size-is-same/style.json index a3267fcf5e..839a8d4a12 100644 --- a/render-test/tests/file-size/pass-size-is-same/style.json +++ b/render-test/tests/file-size/pass-size-is-same/style.json @@ -3,8 +3,8 @@ "metadata": { "test": { "operations": [ - ["probeFileSize", "style", "style.json"], - ["probeFileSize", "image", "expected.png"] + ["probeFileSize", "style", "style.json", 0], + ["probeFileSize", "image", "expected.png", 0] ], "width": 64, "height": 64 -- cgit v1.2.1 From 465d4e8cfa612970dfe4dea0733e88698d7b7e57 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Sun, 13 Oct 2019 18:37:39 +0300 Subject: [render-test] Add test for file size tolerance --- .../pass-size-is-in-tolerance-higher/expected.png | Bin 0 -> 169 bytes .../pass-size-is-in-tolerance-higher/metrics.json | 14 +++++++++ .../pass-size-is-in-tolerance-higher/style.json | 32 +++++++++++++++++++++ .../pass-size-is-in-tolerance-lower/expected.png | Bin 0 -> 169 bytes .../pass-size-is-in-tolerance-lower/metrics.json | 14 +++++++++ .../pass-size-is-in-tolerance-lower/style.json | 32 +++++++++++++++++++++ 6 files changed, 92 insertions(+) create mode 100644 render-test/tests/file-size/pass-size-is-in-tolerance-higher/expected.png create mode 100644 render-test/tests/file-size/pass-size-is-in-tolerance-higher/metrics.json create mode 100644 render-test/tests/file-size/pass-size-is-in-tolerance-higher/style.json create mode 100644 render-test/tests/file-size/pass-size-is-in-tolerance-lower/expected.png create mode 100644 render-test/tests/file-size/pass-size-is-in-tolerance-lower/metrics.json create mode 100644 render-test/tests/file-size/pass-size-is-in-tolerance-lower/style.json diff --git a/render-test/tests/file-size/pass-size-is-in-tolerance-higher/expected.png b/render-test/tests/file-size/pass-size-is-in-tolerance-higher/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/pass-size-is-in-tolerance-higher/expected.png differ diff --git a/render-test/tests/file-size/pass-size-is-in-tolerance-higher/metrics.json b/render-test/tests/file-size/pass-size-is-in-tolerance-higher/metrics.json new file mode 100644 index 0000000000..d0c0c9d7b6 --- /dev/null +++ b/render-test/tests/file-size/pass-size-is-in-tolerance-higher/metrics.json @@ -0,0 +1,14 @@ +{ + "file-size": [ + [ + "image", + "expected.png", + 177 + ], + [ + "style", + "style.json", + 548 + ] + ] +} diff --git a/render-test/tests/file-size/pass-size-is-in-tolerance-higher/style.json b/render-test/tests/file-size/pass-size-is-in-tolerance-higher/style.json new file mode 100644 index 0000000000..d021673ba5 --- /dev/null +++ b/render-test/tests/file-size/pass-size-is-in-tolerance-higher/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json", 0.05], + ["probeFileSize", "image", "expected.png", 0.05] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/file-size/pass-size-is-in-tolerance-lower/expected.png b/render-test/tests/file-size/pass-size-is-in-tolerance-lower/expected.png new file mode 100644 index 0000000000..83d01c4e5d Binary files /dev/null and b/render-test/tests/file-size/pass-size-is-in-tolerance-lower/expected.png differ diff --git a/render-test/tests/file-size/pass-size-is-in-tolerance-lower/metrics.json b/render-test/tests/file-size/pass-size-is-in-tolerance-lower/metrics.json new file mode 100644 index 0000000000..d62b751d5a --- /dev/null +++ b/render-test/tests/file-size/pass-size-is-in-tolerance-lower/metrics.json @@ -0,0 +1,14 @@ +{ + "file-size": [ + [ + "image", + "expected.png", + 161 + ], + [ + "style", + "style.json", + 498 + ] + ] +} diff --git a/render-test/tests/file-size/pass-size-is-in-tolerance-lower/style.json b/render-test/tests/file-size/pass-size-is-in-tolerance-lower/style.json new file mode 100644 index 0000000000..d021673ba5 --- /dev/null +++ b/render-test/tests/file-size/pass-size-is-in-tolerance-lower/style.json @@ -0,0 +1,32 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeFileSize", "style", "style.json", 0.05], + ["probeFileSize", "image", "expected.png", 0.05] + ], + "width": 64, + "height": 64 + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} -- cgit v1.2.1 From 0f9666ebf3614dcc50e6a60c3c84bb578986bcf7 Mon Sep 17 00:00:00 2001 From: tobrun Date: Tue, 15 Oct 2019 10:01:59 +0200 Subject: [android] - remove snapshot and release builds, disable broken metric collection script --- circle.yml | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/circle.yml b/circle.yml index d549cbe563..de57cc6438 100644 --- a/circle.yml +++ b/circle.yml @@ -893,17 +893,6 @@ jobs: path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so.gz - store_artifacts: path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so.gz - - deploy: - name: Publish to Bintray - command: | - if [[ $CIRCLE_BRANCH == master ]] || [[ $CIRCLE_BRANCH == release-* ]] || [[ $CIRCLE_TAG == android-v* ]]; then - version=$(cat platform/android/MapboxGLAndroidSDK/gradle.properties | grep "VERSION_NAME") - if [[ $version != *"SNAPSHOT"* ]]; then - make run-android-upload-to-bintray - else - make run-android-upload-to-artifactory - fi - fi - run: name: Trigger external deploy steps command: | @@ -912,9 +901,9 @@ jobs: export DOCS_REPO="android-docs" scripts/trigger-maps-documentation-deploy-steps.sh background: true - - run: - name: Record size - command: platform/android/scripts/metrics.sh +# - run: +# name: Record size +# command: platform/android/scripts/metrics.sh # ------------------------------------------------------------------------------ android-debug-arm-v7-buck: docker: -- cgit v1.2.1 From e829d1ae6f01ff3c336cd429dacd98aeb3b7162a Mon Sep 17 00:00:00 2001 From: zmiao Date: Tue, 15 Oct 2019 19:16:32 +0300 Subject: [test-runner] make render-test a shared lib (#15816) * [test-runner] make render-test a shared lib [test-runner] nit [test-runner] nit again * [test-runner] Remove redundant linked file in cmake --- cmake/render-test.cmake | 58 ++++++--- next/CMakeLists.txt | 1 + next/platform/linux/linux.cmake | 27 +++- next/platform/macos/macos.cmake | 28 ++++- next/render-test/CMakeLists.txt | 37 +++--- platform/default/src/mbgl/render-test/main.cpp | 5 + render-test/include/mbgl/render_test.hpp | 9 ++ render-test/main.cpp | 162 ------------------------ render-test/render_test.cpp | 167 +++++++++++++++++++++++++ 9 files changed, 294 insertions(+), 200 deletions(-) create mode 100644 platform/default/src/mbgl/render-test/main.cpp create mode 100644 render-test/include/mbgl/render_test.hpp delete mode 100644 render-test/main.cpp create mode 100644 render-test/render_test.cpp diff --git a/cmake/render-test.cmake b/cmake/render-test.cmake index 65240b54f3..8726fb4650 100644 --- a/cmake/render-test.cmake +++ b/cmake/render-test.cmake @@ -1,32 +1,60 @@ -add_executable(mbgl-render-test +add_executable( + mbgl-render-test + expression-test/test_runner_common.cpp + expression-test/test_runner_common.hpp + platform/default/src/mbgl/render-test/main.cpp render-test/allocation_index.cpp - render-test/main.cpp + render-test/allocation_index.hpp + render-test/filesystem.hpp + render-test/filesystem.hpp + render-test/include/mbgl/render_test.hpp + render-test/metadata.hpp render-test/parser.cpp + render-test/parser.hpp + render-test/render_test.cpp render-test/runner.cpp - expression-test/test_runner_common.cpp - expression-test/test_runner_common.hpp + render-test/runner.hpp ) if(APPLE) - target_link_libraries(mbgl-render-test PRIVATE mbgl-loop-darwin) + target_link_libraries( + mbgl-render-test + PRIVATE mbgl-loop-darwin + ) else() - target_link_libraries(mbgl-render-test PRIVATE mbgl-loop-uv) + target_link_libraries( + mbgl-render-test + PRIVATE mbgl-loop-uv + ) endif() -target_include_directories(mbgl-render-test +target_include_directories( + mbgl-render-test PRIVATE src PRIVATE platform/default/include PRIVATE render-test ) -target_link_libraries(mbgl-render-test PRIVATE - mbgl-core - mbgl-filesource - Mapbox::Base::Extras::args - mbgl-vendor-expected - Mapbox::Base::Extras::filesystem - Mapbox::Base::pixelmatch-cpp - Mapbox::Base::Extras::rapidjson +target_include_directories( + mbgl-render-test + PUBLIC render-test/include + PUBLIC include ) +target_link_libraries( + mbgl-render-test + PRIVATE + mbgl-core + mbgl-filesource + Mapbox::Base::Extras::args + mbgl-vendor-expected + Mapbox::Base::Extras::filesystem + Mapbox::Base::pixelmatch-cpp + Mapbox::Base::Extras::rapidjson +) + +create_source_groups(mbgl-render-test) + +set_target_properties(mbgl-render-test PROPERTIES FOLDER "Executables") + add_definitions(-DTEST_RUNNER_ROOT_PATH="${CMAKE_SOURCE_DIR}") diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index df56f04b22..fb0779bea4 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -943,3 +943,4 @@ endif() add_subdirectory(${PROJECT_SOURCE_DIR}/test) add_subdirectory(${PROJECT_SOURCE_DIR}/benchmark) +add_subdirectory(${PROJECT_SOURCE_DIR}/render-test) diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 18531a2856..be905c204f 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -95,7 +95,6 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/bin) add_subdirectory(${PROJECT_SOURCE_DIR}/expression-test) add_subdirectory(${PROJECT_SOURCE_DIR}/platform/glfw) add_subdirectory(${PROJECT_SOURCE_DIR}/platform/node) -add_subdirectory(${PROJECT_SOURCE_DIR}/render-test) add_executable( mbgl-test-runner @@ -122,5 +121,31 @@ target_link_libraries( PRIVATE mbgl-benchmark ) +add_executable( + mbgl-render-test-runner + ${MBGL_ROOT}/platform/default/src/mbgl/render-test/main.cpp +) + +target_link_libraries( + mbgl-render-test-runner + PRIVATE mbgl-render-test +) + add_test(NAME mbgl-benchmark-runner COMMAND mbgl-benchmark-runner WORKING_DIRECTORY ${MBGL_ROOT}) add_test(NAME mbgl-test-runner COMMAND mbgl-test-runner WORKING_DIRECTORY ${MBGL_ROOT}) + +string(RANDOM LENGTH 5 ALPHABET 0123456789 MBGL_RENDER_TEST_SEED) + +add_test( + NAME mbgl-render-test + COMMAND + mbgl-render-test-runner + render-tests + --recycle-map + --shuffle + --seed=${MBGL_RENDER_TEST_SEED} + WORKING_DIRECTORY ${MBGL_ROOT} +) + +add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test-runner tests --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT}) +add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests WORKING_DIRECTORY ${MBGL_ROOT}) diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index a0dcb9a829..cbe386a1ac 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -155,7 +155,6 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/bin) add_subdirectory(${PROJECT_SOURCE_DIR}/expression-test) add_subdirectory(${PROJECT_SOURCE_DIR}/platform/glfw) add_subdirectory(${PROJECT_SOURCE_DIR}/platform/node) -add_subdirectory(${PROJECT_SOURCE_DIR}/render-test) add_executable( mbgl-test-runner @@ -182,8 +181,35 @@ target_link_libraries( PRIVATE mbgl-benchmark ) +add_executable( + mbgl-render-test-runner + ${MBGL_ROOT}/platform/default/src/mbgl/render-test/main.cpp +) + +target_link_libraries( + mbgl-render-test-runner + PRIVATE mbgl-render-test +) + set_property(TARGET mbgl-benchmark-runner PROPERTY FOLDER Executables) set_property(TARGET mbgl-test-runner PROPERTY FOLDER Executables) +set_property(TARGET mbgl-render-test-runner PROPERTY FOLDER Executables) add_test(NAME mbgl-benchmark-runner COMMAND mbgl-benchmark-runner WORKING_DIRECTORY ${MBGL_ROOT}) add_test(NAME mbgl-test-runner COMMAND mbgl-test-runner WORKING_DIRECTORY ${MBGL_ROOT}) + +string(RANDOM LENGTH 5 ALPHABET 0123456789 MBGL_RENDER_TEST_SEED) + +add_test( + NAME mbgl-render-test + COMMAND + mbgl-render-test-runner + render-tests + --recycle-map + --shuffle + --seed=${MBGL_RENDER_TEST_SEED} + WORKING_DIRECTORY ${MBGL_ROOT} +) + +add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test-runner tests --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT}) +add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests WORKING_DIRECTORY ${MBGL_ROOT}) diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 1a4cd5ceb6..2e1c5438ed 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -1,16 +1,18 @@ -add_executable( - mbgl-render-test +add_library( + mbgl-render-test SHARED EXCLUDE_FROM_ALL + ${MBGL_ROOT}/expression-test/test_runner_common.cpp + ${MBGL_ROOT}/expression-test/test_runner_common.hpp ${MBGL_ROOT}/render-test/allocation_index.cpp ${MBGL_ROOT}/render-test/allocation_index.hpp ${MBGL_ROOT}/render-test/filesystem.hpp - ${MBGL_ROOT}/render-test/main.cpp + ${MBGL_ROOT}/render-test/filesystem.hpp + ${MBGL_ROOT}/render-test/include/mbgl/render_test.hpp ${MBGL_ROOT}/render-test/metadata.hpp ${MBGL_ROOT}/render-test/parser.cpp ${MBGL_ROOT}/render-test/parser.hpp + ${MBGL_ROOT}/render-test/render_test.cpp ${MBGL_ROOT}/render-test/runner.cpp ${MBGL_ROOT}/render-test/runner.hpp - ${MBGL_ROOT}/expression-test/test_runner_common.cpp - ${MBGL_ROOT}/expression-test/test_runner_common.hpp ) target_compile_definitions( @@ -24,6 +26,11 @@ target_include_directories( PRIVATE ${MBGL_ROOT}/src ) +target_include_directories( + mbgl-render-test + PUBLIC ${MBGL_ROOT}/render-test/include ${MBGL_ROOT}/include +) + include(${PROJECT_SOURCE_DIR}/vendor/boost.cmake) target_link_libraries( @@ -36,20 +43,8 @@ target_link_libraries( mbgl-vendor-boost ) -set_property(TARGET mbgl-render-test PROPERTY FOLDER Executables) - -string(RANDOM LENGTH 5 ALPHABET 0123456789 MBGL_RENDER_TEST_SEED) - -add_test( - NAME mbgl-render-test - COMMAND - mbgl-render-test - render-tests - --recycle-map - --shuffle - --seed=${MBGL_RENDER_TEST_SEED} - WORKING_DIRECTORY ${MBGL_ROOT} -) +if(CMAKE_SYSTEM_NAME STREQUAL Android) + set_target_properties(mbgl-render-test PROPERTIES LINK_FLAGS_RELEASE "-fuse-ld=gold -O2 -flto -Wl,--icf=safe") +endif() -add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test tests --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT}) -add_test(NAME mbgl-query-test COMMAND mbgl-render-test query-tests WORKING_DIRECTORY ${MBGL_ROOT}) +set_property(TARGET mbgl-render-test PROPERTY FOLDER Core) diff --git a/platform/default/src/mbgl/render-test/main.cpp b/platform/default/src/mbgl/render-test/main.cpp new file mode 100644 index 0000000000..9b22b20e00 --- /dev/null +++ b/platform/default/src/mbgl/render-test/main.cpp @@ -0,0 +1,5 @@ +#include + +int main(int argc, char *argv[]) { + return mbgl::runRenderTests(argc, argv); +} diff --git a/render-test/include/mbgl/render_test.hpp b/render-test/include/mbgl/render_test.hpp new file mode 100644 index 0000000000..42a539603d --- /dev/null +++ b/render-test/include/mbgl/render_test.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace mbgl { + +MBGL_EXPORT int runRenderTests(int argc, char* argv[]); + +} // namespace mbgl diff --git a/render-test/main.cpp b/render-test/main.cpp deleted file mode 100644 index 6f5e2449a9..0000000000 --- a/render-test/main.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "allocation_index.hpp" - -#include -#include - -#include "metadata.hpp" -#include "parser.hpp" -#include "runner.hpp" - -#include - -#define ANSI_COLOR_RED "\x1b[31m" -#define ANSI_COLOR_GREEN "\x1b[32m" -#define ANSI_COLOR_YELLOW "\x1b[33m" -#define ANSI_COLOR_BLUE "\x1b[34m" -#define ANSI_COLOR_MAGENTA "\x1b[35m" -#define ANSI_COLOR_CYAN "\x1b[36m" -#define ANSI_COLOR_GRAY "\x1b[37m" -#define ANSI_COLOR_LIGHT_GRAY "\x1b[90m" -#define ANSI_COLOR_RESET "\x1b[0m" - -#if !defined(SANITIZE) -void* operator new(std::size_t sz) { - void* ptr = AllocationIndex::allocate(sz); - if (!ptr) throw std::bad_alloc{}; - - return ptr; -} - -void operator delete(void* ptr) noexcept { - AllocationIndex::deallocate(ptr); -} - -void operator delete(void* ptr, size_t) noexcept { - AllocationIndex::deallocate(ptr); -} -#endif - -int main(int argc, char** argv) { - bool recycleMap; - bool shuffle; - uint32_t seed; - std::string testRootPath; - std::vector testPaths; - - std::tie(recycleMap, shuffle, seed, testRootPath, testPaths) = parseArguments(argc, argv); - const std::string::size_type rootLength = testRootPath.length(); - - const auto ignores = parseIgnores(); - - if (shuffle) { - printf(ANSI_COLOR_YELLOW "Shuffle seed: %d" ANSI_COLOR_RESET "\n", seed); - - std::seed_seq sequence { seed }; - std::mt19937 shuffler(sequence); - std::shuffle(testPaths.begin(), testPaths.end(), shuffler); - } - - mbgl::util::RunLoop runLoop; - TestRunner runner; - - std::vector metadatas; - metadatas.reserve(testPaths.size()); - - TestStatistics stats; - - for (auto& testPath : testPaths) { - TestMetadata metadata = parseTestMetadata(testPath); - - if (!recycleMap) { - runner.reset(); - } - - std::string& id = metadata.id; - std::string& status = metadata.status; - std::string& color = metadata.color; - - id = testPath.defaultExpectations(); - id = id.substr(rootLength + 1, id.length() - rootLength - 2); - - bool shouldIgnore = false; - std::string ignoreReason; - - const std::string ignoreName = id; - const auto it = std::find_if(ignores.cbegin(), ignores.cend(), [&ignoreName](auto pair) { return pair.first == ignoreName; }); - if (it != ignores.end()) { - shouldIgnore = true; - ignoreReason = it->second; - if (ignoreReason.rfind("skip", 0) == 0) { - printf(ANSI_COLOR_GRAY "* skipped %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str()); - continue; - } - } - - bool errored = !metadata.errorMessage.empty(); - if (!errored) { - errored = !runner.run(metadata) || !metadata.errorMessage.empty(); - } - - bool passed = !errored && !metadata.diff.empty() && metadata.difference <= metadata.allowed; - - if (shouldIgnore) { - if (passed) { - status = "ignored passed"; - color = "#E8A408"; - stats.ignorePassedTests++; - printf(ANSI_COLOR_YELLOW "* ignore %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str()); - } else { - status = "ignored failed"; - color = "#9E9E9E"; - stats.ignoreFailedTests++; - printf(ANSI_COLOR_LIGHT_GRAY "* ignore %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str()); - } - } else { - if (passed) { - status = "passed"; - color = "green"; - stats.passedTests++; - printf(ANSI_COLOR_GREEN "* passed %s" ANSI_COLOR_RESET "\n", id.c_str()); - } else if (errored) { - status = "errored"; - color = "red"; - stats.erroredTests++; - printf(ANSI_COLOR_RED "* errored %s" ANSI_COLOR_RESET "\n", id.c_str()); - } else { - status = "failed"; - color = "red"; - stats.failedTests++; - printf(ANSI_COLOR_RED "* failed %s" ANSI_COLOR_RESET "\n", id.c_str()); - } - } - - metadatas.push_back(std::move(metadata)); - } - - std::string resultsHTML = createResultPage(stats, metadatas, shuffle, seed); - mbgl::util::write_file(testRootPath + "/index.html", resultsHTML); - - const uint32_t count = stats.erroredTests + stats.failedTests + - stats.ignoreFailedTests + stats.ignorePassedTests + - stats.passedTests; - - if (stats.passedTests) { - printf(ANSI_COLOR_GREEN "%u passed (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.passedTests, 100.0 * stats.passedTests / count); - } - if (stats.ignorePassedTests) { - printf(ANSI_COLOR_YELLOW "%u passed but were ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.ignorePassedTests, 100.0 * stats.ignorePassedTests / count); - } - if (stats.ignoreFailedTests) { - printf(ANSI_COLOR_LIGHT_GRAY "%u ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.ignoreFailedTests, 100.0 * stats.ignoreFailedTests / count); - } - if (stats.failedTests) { - printf(ANSI_COLOR_RED "%u failed (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.failedTests, 100.0 * stats.failedTests / count); - } - if (stats.erroredTests) { - printf(ANSI_COLOR_RED "%u errored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.erroredTests, 100.0 * stats.erroredTests / count); - } - - printf("Results at: %s%s\n", testRootPath.c_str(), "/index.html"); - - return stats.failedTests + stats.erroredTests == 0 ? 0 : 1; -} diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp new file mode 100644 index 0000000000..bac193237d --- /dev/null +++ b/render-test/render_test.cpp @@ -0,0 +1,167 @@ +#include "allocation_index.hpp" + +#include +#include +#include + +#include "metadata.hpp" +#include "parser.hpp" +#include "runner.hpp" + +#include + +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_GRAY "\x1b[37m" +#define ANSI_COLOR_LIGHT_GRAY "\x1b[90m" +#define ANSI_COLOR_RESET "\x1b[0m" + +#if !defined(SANITIZE) +void* operator new(std::size_t sz) { + void* ptr = AllocationIndex::allocate(sz); + if (!ptr) throw std::bad_alloc{}; + + return ptr; +} + +void operator delete(void* ptr) noexcept { + AllocationIndex::deallocate(ptr); +} + +void operator delete(void* ptr, size_t) noexcept { + AllocationIndex::deallocate(ptr); +} +#endif + +namespace mbgl { + +int runRenderTests(int argc, char** argv) { + bool recycleMap; + bool shuffle; + uint32_t seed; + std::string testRootPath; + std::vector testPaths; + + std::tie(recycleMap, shuffle, seed, testRootPath, testPaths) = parseArguments(argc, argv); + const std::string::size_type rootLength = testRootPath.length(); + + const auto ignores = parseIgnores(); + + if (shuffle) { + printf(ANSI_COLOR_YELLOW "Shuffle seed: %d" ANSI_COLOR_RESET "\n", seed); + + std::seed_seq sequence { seed }; + std::mt19937 shuffler(sequence); + std::shuffle(testPaths.begin(), testPaths.end(), shuffler); + } + + mbgl::util::RunLoop runLoop; + TestRunner runner; + + std::vector metadatas; + metadatas.reserve(testPaths.size()); + + TestStatistics stats; + + for (auto& testPath : testPaths) { + TestMetadata metadata = parseTestMetadata(testPath); + + if (!recycleMap) { + runner.reset(); + } + + std::string& id = metadata.id; + std::string& status = metadata.status; + std::string& color = metadata.color; + + id = testPath.defaultExpectations(); + id = id.substr(rootLength + 1, id.length() - rootLength - 2); + + bool shouldIgnore = false; + std::string ignoreReason; + + const std::string ignoreName = id; + const auto it = std::find_if(ignores.cbegin(), ignores.cend(), [&ignoreName](auto pair) { return pair.first == ignoreName; }); + if (it != ignores.end()) { + shouldIgnore = true; + ignoreReason = it->second; + if (ignoreReason.rfind("skip", 0) == 0) { + printf(ANSI_COLOR_GRAY "* skipped %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str()); + continue; + } + } + + bool errored = !metadata.errorMessage.empty(); + if (!errored) { + errored = !runner.run(metadata) || !metadata.errorMessage.empty(); + } + + bool passed = !errored && !metadata.diff.empty() && metadata.difference <= metadata.allowed; + + if (shouldIgnore) { + if (passed) { + status = "ignored passed"; + color = "#E8A408"; + stats.ignorePassedTests++; + printf(ANSI_COLOR_YELLOW "* ignore %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str()); + } else { + status = "ignored failed"; + color = "#9E9E9E"; + stats.ignoreFailedTests++; + printf(ANSI_COLOR_LIGHT_GRAY "* ignore %s (%s)" ANSI_COLOR_RESET "\n", id.c_str(), ignoreReason.c_str()); + } + } else { + if (passed) { + status = "passed"; + color = "green"; + stats.passedTests++; + printf(ANSI_COLOR_GREEN "* passed %s" ANSI_COLOR_RESET "\n", id.c_str()); + } else if (errored) { + status = "errored"; + color = "red"; + stats.erroredTests++; + printf(ANSI_COLOR_RED "* errored %s" ANSI_COLOR_RESET "\n", id.c_str()); + } else { + status = "failed"; + color = "red"; + stats.failedTests++; + printf(ANSI_COLOR_RED "* failed %s" ANSI_COLOR_RESET "\n", id.c_str()); + } + } + + metadatas.push_back(std::move(metadata)); + } + + std::string resultsHTML = createResultPage(stats, metadatas, shuffle, seed); + mbgl::util::write_file(testRootPath + "/index.html", resultsHTML); + + const uint32_t count = stats.erroredTests + stats.failedTests + + stats.ignoreFailedTests + stats.ignorePassedTests + + stats.passedTests; + + if (stats.passedTests) { + printf(ANSI_COLOR_GREEN "%u passed (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.passedTests, 100.0 * stats.passedTests / count); + } + if (stats.ignorePassedTests) { + printf(ANSI_COLOR_YELLOW "%u passed but were ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.ignorePassedTests, 100.0 * stats.ignorePassedTests / count); + } + if (stats.ignoreFailedTests) { + printf(ANSI_COLOR_LIGHT_GRAY "%u ignored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.ignoreFailedTests, 100.0 * stats.ignoreFailedTests / count); + } + if (stats.failedTests) { + printf(ANSI_COLOR_RED "%u failed (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.failedTests, 100.0 * stats.failedTests / count); + } + if (stats.erroredTests) { + printf(ANSI_COLOR_RED "%u errored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.erroredTests, 100.0 * stats.erroredTests / count); + } + + printf("Results at: %s%s\n", testRootPath.c_str(), "/index.html"); + + return stats.failedTests + stats.erroredTests == 0 ? 0 : 1; +} + +} // namespace mbgl \ No newline at end of file -- cgit v1.2.1 From ee2b8033153bff0baeb5973dd400e5f867d86e03 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 15 Oct 2019 14:38:43 -0700 Subject: [build] Update to Xcode 11.1 --- circle.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/circle.yml b/circle.yml index de57cc6438..b45a623866 100644 --- a/circle.yml +++ b/circle.yml @@ -194,7 +194,7 @@ executors: QT_VERSION: 5 macos-11_0_0: macos: - xcode: '11.0.0' + xcode: '11.1.0' environment: HOMEBREW_NO_AUTO_UPDATE: 1 HOMEBREW_NO_INSTALL_CLEANUP: 1 @@ -933,7 +933,7 @@ jobs: # ------------------------------------------------------------------------------ node-macos-release: macos: - xcode: "11.0.0" + xcode: "11.1.0" environment: BUILDTYPE: RelWithDebInfo HOMEBREW_NO_AUTO_UPDATE: 1 @@ -1057,7 +1057,7 @@ jobs: # ------------------------------------------------------------------------------ ios-debug: macos: - xcode: "11.0.0" + xcode: "11.1.0" environment: BUILDTYPE: Debug HOMEBREW_NO_AUTO_UPDATE: 1 @@ -1105,7 +1105,7 @@ jobs: # ------------------------------------------------------------------------------ ios-sanitize-nightly: macos: - xcode: "11.0.0" + xcode: "11.1.0" environment: BUILDTYPE: Debug HOMEBREW_NO_AUTO_UPDATE: 1 @@ -1132,7 +1132,7 @@ jobs: # ------------------------------------------------------------------------------ ios-sanitize-address-nightly: macos: - xcode: "11.0.0" + xcode: "11.1.0" environment: BUILDTYPE: Debug HOMEBREW_NO_AUTO_UPDATE: 1 @@ -1152,7 +1152,7 @@ jobs: # ------------------------------------------------------------------------------ ios-static-analyzer-nightly: macos: - xcode: "11.0.0" + xcode: "11.1.0" environment: BUILDTYPE: Debug HOMEBREW_NO_AUTO_UPDATE: 1 @@ -1192,7 +1192,7 @@ jobs: # ------------------------------------------------------------------------------ ios-release-template: macos: - xcode: "11.0.0" + xcode: "11.1.0" shell: /bin/bash --login -eo pipefail environment: BUILDTYPE: Release -- cgit v1.2.1 From b53093b5221efb6f98f712f734b823ffce1400e1 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Thu, 10 Oct 2019 12:17:34 +0300 Subject: [render-test] Add support for collecting network metrics --- next/render-test/CMakeLists.txt | 3 +- render-test/file_source.cpp | 65 +++++++++++++++++++++++++++++++++++++++++ render-test/file_source.hpp | 40 +++++++++++++++++++++++++ render-test/metadata.hpp | 11 ++++++- render-test/parser.cpp | 34 +++++++++++++++++++++ render-test/runner.cpp | 53 +++++++++++++++++++++++++++++++++ 6 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 render-test/file_source.cpp create mode 100644 render-test/file_source.hpp diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 2e1c5438ed..b3aa20ba62 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -4,7 +4,8 @@ add_library( ${MBGL_ROOT}/expression-test/test_runner_common.hpp ${MBGL_ROOT}/render-test/allocation_index.cpp ${MBGL_ROOT}/render-test/allocation_index.hpp - ${MBGL_ROOT}/render-test/filesystem.hpp + ${MBGL_ROOT}/render-test/file_source.cpp + ${MBGL_ROOT}/render-test/file_source.hpp ${MBGL_ROOT}/render-test/filesystem.hpp ${MBGL_ROOT}/render-test/include/mbgl/render_test.hpp ${MBGL_ROOT}/render-test/metadata.hpp diff --git a/render-test/file_source.cpp b/render-test/file_source.cpp new file mode 100644 index 0000000000..0968f1d2f0 --- /dev/null +++ b/render-test/file_source.cpp @@ -0,0 +1,65 @@ +#include + +#include "file_source.hpp" + +namespace mbgl { + +std::atomic_size_t requestCount{0}; +std::atomic_size_t transferredSize{0}; +std::atomic_bool active{false}; + +ProxyFileSource::ProxyFileSource(const std::string& cachePath, + const std::string& assetPath, + bool supportCacheOnlyRequests_) + : DefaultFileSource(cachePath, assetPath, supportCacheOnlyRequests_) {} + +ProxyFileSource::ProxyFileSource(const std::string& cachePath, + std::unique_ptr&& assetFileSource_, + bool supportCacheOnlyRequests_) + : DefaultFileSource(cachePath, std::move(assetFileSource_), supportCacheOnlyRequests_) {} + +ProxyFileSource::~ProxyFileSource() = default; + +std::unique_ptr ProxyFileSource::request(const Resource& resource, Callback callback) { + auto result = DefaultFileSource::request(resource, [=](Response response) { + std::size_t size = response.data != nullptr ? response.data->size() : 0; + if (active) { + requestCount++; + transferredSize += size; + } + callback(response); + }); + return result; +} + +std::shared_ptr FileSource::createPlatformFileSource(const ResourceOptions& options) { + auto fileSource = std::make_shared( + options.cachePath(), options.assetPath(), options.supportsCacheOnlyRequests()); + fileSource->setAccessToken(options.accessToken()); + fileSource->setAPIBaseURL(options.baseURL()); + return fileSource; +} + +// static +void ProxyFileSource::setTrackingActive(bool active_) { + active = active_; + requestCount = 0; + transferredSize = 0; +} + +// static +bool ProxyFileSource::isTrackingActive() { + return active; +} + +// static +size_t ProxyFileSource::getRequestCount() { + return requestCount; +} + +// static +size_t ProxyFileSource::getTransferredSize() { + return transferredSize; +} + +} // namespace mbgl diff --git a/render-test/file_source.hpp b/render-test/file_source.hpp new file mode 100644 index 0000000000..58acf7b6ad --- /dev/null +++ b/render-test/file_source.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace mbgl { + +class ProxyFileSource : public DefaultFileSource { +public: + ProxyFileSource(const std::string& cachePath, const std::string& assetPath, bool supportCacheOnlyRequests = true); + ProxyFileSource(const std::string& cachePath, + std::unique_ptr&& assetFileSource, + bool supportCacheOnlyRequests = true); + ~ProxyFileSource(); + + std::unique_ptr request(const Resource&, Callback); + + /** + * @brief Starts/stops metrics tracking. + */ + static void setTrackingActive(bool); + /** + * @brief Returns metrics tracking status. + */ + static bool isTrackingActive(); + /** + * @brief Returns the total amount of requests. + * + * @return size_t + */ + static size_t getRequestCount(); + + /** + * @brief Returns the size of transferred data (in bytes). + * + * @return size_t + */ + static size_t getTransferredSize(); +}; + +} // namespace mbgl diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index bd26e6a7ba..c26fde1d19 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -57,11 +57,20 @@ struct MemoryProbe { size_t allocations; }; +struct NetworkProbe { + NetworkProbe() = default; + NetworkProbe(size_t requests_, size_t transferred_) : requests(requests_), transferred(transferred_) {} + + size_t requests; + size_t transferred; +}; + class TestMetrics { public: - bool isEmpty() const { return fileSize.empty() && memory.empty(); } + bool isEmpty() const { return fileSize.empty() && memory.empty() && network.empty(); } std::map fileSize; std::map memory; + std::map network; }; struct TestMetadata { diff --git a/render-test/parser.cpp b/render-test/parser.cpp index f4e54493eb..41c9b83298 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -304,6 +304,21 @@ std::string serializeMetrics(const TestMetrics& metrics) { writer.EndArray(); } + // Start network section + if (!metrics.network.empty()) { + writer.Key("network"); + writer.StartArray(); + for (const auto& networkProbe : metrics.network) { + assert(!networkProbe.first.empty()); + writer.StartArray(); + writer.String(networkProbe.first.c_str()); + writer.Uint64(networkProbe.second.requests); + writer.Uint64(networkProbe.second.transferred); + writer.EndArray(); + } + writer.EndArray(); + } + writer.EndObject(); return s.GetString(); @@ -500,6 +515,25 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { } } + if (document.HasMember("network")) { + const mbgl::JSValue& networkValue = document["network"]; + assert(networkValue.IsArray()); + for (auto& probeValue : networkValue.GetArray()) { + assert(probeValue.IsArray()); + assert(probeValue.Size() >= 3u); + assert(probeValue[0].IsString()); + assert(probeValue[1].IsNumber()); + assert(probeValue[2].IsNumber()); + + std::string mark{probeValue[0].GetString(), probeValue[0].GetStringLength()}; + assert(!mark.empty()); + + result.network.emplace(std::piecewise_construct, + std::forward_as_tuple(std::move(mark)), + std::forward_as_tuple(probeValue[1].GetUint64(), probeValue[2].GetUint64())); + } + } + return result; } diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 3594c9488b..810806d231 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -21,6 +21,7 @@ #include <../expression-test/test_runner_common.hpp> #include "allocation_index.hpp" +#include "file_source.hpp" #include "metadata.hpp" #include "parser.hpp" #include "runner.hpp" @@ -294,6 +295,35 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, } } + // Check network metrics. + for (const auto& expected : metadata.expectedMetrics.network) { + auto actual = metadata.metrics.network.find(expected.first); + if (actual == metadata.metrics.network.end()) { + metadata.errorMessage = "Failed to find network probe: " + expected.first; + return false; + } + bool failed = false; + if (actual->second.requests != expected.second.requests) { + std::stringstream ss; + ss << "Number of requests at probe \"" << expected.first << "\" is " << actual->second.requests + << ", expected is " << expected.second.requests << ". "; + + metadata.errorMessage = ss.str(); + failed = true; + } + if (actual->second.transferred != expected.second.transferred) { + std::stringstream ss; + ss << "Transferred data at probe \"" << expected.first << "\" is " << actual->second.transferred + << " bytes, expected is " << expected.second.transferred << " bytes."; + + metadata.errorMessage += ss.str(); + failed = true; + } + if (failed) { + return false; + } + } + return true; } @@ -343,6 +373,9 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { static const std::string memoryProbeOp("probeMemory"); static const std::string memoryProbeStartOp("probeMemoryStart"); static const std::string memoryProbeEndOp("probeMemoryEnd"); + static const std::string networkProbeOp("probeNetwork"); + static const std::string networkProbeStartOp("probeNetworkStart"); + static const std::string networkProbeEndOp("probeNetworkEnd"); static const std::string setFeatureStateOp("setFeatureState"); static const std::string getFeatureStateOp("getFeatureState"); static const std::string removeFeatureStateOp("removeFeatureState"); @@ -619,6 +652,25 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(AllocationIndex::isActive()); AllocationIndex::setActive(false); AllocationIndex::reset(); + } else if (operationArray[0].GetString() == networkProbeStartOp) { + // probeNetworkStart + assert(!ProxyFileSource::isTrackingActive()); + ProxyFileSource::setTrackingActive(true); + } else if (operationArray[0].GetString() == networkProbeOp) { + // probeNetwork + assert(ProxyFileSource::isTrackingActive()); + assert(operationArray.Size() >= 2u); + assert(operationArray[1].IsString()); + std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength()); + + metadata.metrics.network.emplace( + std::piecewise_construct, + std::forward_as_tuple(std::move(mark)), + std::forward_as_tuple(ProxyFileSource::getRequestCount(), ProxyFileSource::getTransferredSize())); + } else if (operationArray[0].GetString() == networkProbeEndOp) { + // probeNetworkEnd + assert(ProxyFileSource::isTrackingActive()); + ProxyFileSource::setTrackingActive(false); } else if (operationArray[0].GetString() == setFeatureStateOp) { // setFeatureState assert(operationArray.Size() >= 3u); @@ -786,6 +838,7 @@ TestRunner::Impl::Impl(const TestMetadata& metadata) bool TestRunner::run(TestMetadata& metadata) { AllocationIndex::setActive(false); AllocationIndex::reset(); + ProxyFileSource::setTrackingActive(false); std::string key = mbgl::util::toString(uint32_t(metadata.mapMode)) + "/" + mbgl::util::toString(metadata.pixelRatio) + "/" + mbgl::util::toString(uint32_t(metadata.crossSourceCollisions)); -- cgit v1.2.1 From 050b3360ecef908d02141ed445d93ba5b4c9c75f Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Fri, 11 Oct 2019 11:34:13 +0300 Subject: [render-test] Add network metrics test case --- .../network/fail-requests-transferred/expected.png | Bin 0 -> 17383 bytes .../network/fail-requests-transferred/metrics.json | 14 +++++ .../network/fail-requests-transferred/style.json | 67 +++++++++++++++++++++ .../tests/network/fail-requests/expected.png | Bin 0 -> 17383 bytes .../tests/network/fail-requests/metrics.json | 14 +++++ render-test/tests/network/fail-requests/style.json | 67 +++++++++++++++++++++ .../tests/network/fail-transferred/expected.png | Bin 0 -> 17383 bytes .../tests/network/fail-transferred/metrics.json | 14 +++++ .../tests/network/fail-transferred/style.json | 67 +++++++++++++++++++++ render-test/tests/network/pass/expected.png | Bin 0 -> 17383 bytes render-test/tests/network/pass/metrics.json | 14 +++++ render-test/tests/network/pass/style.json | 67 +++++++++++++++++++++ render-test/tests/should-fail.json | 5 +- 13 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 render-test/tests/network/fail-requests-transferred/expected.png create mode 100644 render-test/tests/network/fail-requests-transferred/metrics.json create mode 100644 render-test/tests/network/fail-requests-transferred/style.json create mode 100644 render-test/tests/network/fail-requests/expected.png create mode 100644 render-test/tests/network/fail-requests/metrics.json create mode 100644 render-test/tests/network/fail-requests/style.json create mode 100644 render-test/tests/network/fail-transferred/expected.png create mode 100644 render-test/tests/network/fail-transferred/metrics.json create mode 100644 render-test/tests/network/fail-transferred/style.json create mode 100644 render-test/tests/network/pass/expected.png create mode 100644 render-test/tests/network/pass/metrics.json create mode 100644 render-test/tests/network/pass/style.json diff --git a/render-test/tests/network/fail-requests-transferred/expected.png b/render-test/tests/network/fail-requests-transferred/expected.png new file mode 100644 index 0000000000..b63b151765 Binary files /dev/null and b/render-test/tests/network/fail-requests-transferred/expected.png differ diff --git a/render-test/tests/network/fail-requests-transferred/metrics.json b/render-test/tests/network/fail-requests-transferred/metrics.json new file mode 100644 index 0000000000..1a200ca38f --- /dev/null +++ b/render-test/tests/network/fail-requests-transferred/metrics.json @@ -0,0 +1,14 @@ +{ + "network": [ + [ + "end", + 2, + 200000 + ], + [ + "start", + 0, + 0 + ] + ] +} \ No newline at end of file diff --git a/render-test/tests/network/fail-requests-transferred/style.json b/render-test/tests/network/fail-requests-transferred/style.json new file mode 100644 index 0000000000..ef94ddc748 --- /dev/null +++ b/render-test/tests/network/fail-requests-transferred/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeNetworkStart"], + ["probeNetwork", "start"], + ["wait"], + ["probeNetwork", "end"], + ["probeNetworkEnd"] + ], + "height": 256, + "width": 1024 + } + }, + "center": [ + -73, + 15 + ], + "zoom": 4.5, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/mapbox.mapbox-streets-v7/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line-center", + "type": "symbol", + "source": "mapbox", + "source-layer": "marine_label", + "layout": { + "text-field": "{name_en}", + "symbol-placement": "line-center", + "text-allow-overlap": true, + "text-size": 35, + "text-letter-spacing": 0.4, + "text-offset": [3, 0], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "line", + "type": "line", + "source": "mapbox", + "source-layer": "marine_label", + "paint": { + "line-width": 1 + } + } + ] +} diff --git a/render-test/tests/network/fail-requests/expected.png b/render-test/tests/network/fail-requests/expected.png new file mode 100644 index 0000000000..b63b151765 Binary files /dev/null and b/render-test/tests/network/fail-requests/expected.png differ diff --git a/render-test/tests/network/fail-requests/metrics.json b/render-test/tests/network/fail-requests/metrics.json new file mode 100644 index 0000000000..81c9b8a5d4 --- /dev/null +++ b/render-test/tests/network/fail-requests/metrics.json @@ -0,0 +1,14 @@ +{ + "network": [ + [ + "end", + 2, + 183111 + ], + [ + "start", + 0, + 0 + ] + ] +} \ No newline at end of file diff --git a/render-test/tests/network/fail-requests/style.json b/render-test/tests/network/fail-requests/style.json new file mode 100644 index 0000000000..ef94ddc748 --- /dev/null +++ b/render-test/tests/network/fail-requests/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeNetworkStart"], + ["probeNetwork", "start"], + ["wait"], + ["probeNetwork", "end"], + ["probeNetworkEnd"] + ], + "height": 256, + "width": 1024 + } + }, + "center": [ + -73, + 15 + ], + "zoom": 4.5, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/mapbox.mapbox-streets-v7/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line-center", + "type": "symbol", + "source": "mapbox", + "source-layer": "marine_label", + "layout": { + "text-field": "{name_en}", + "symbol-placement": "line-center", + "text-allow-overlap": true, + "text-size": 35, + "text-letter-spacing": 0.4, + "text-offset": [3, 0], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "line", + "type": "line", + "source": "mapbox", + "source-layer": "marine_label", + "paint": { + "line-width": 1 + } + } + ] +} diff --git a/render-test/tests/network/fail-transferred/expected.png b/render-test/tests/network/fail-transferred/expected.png new file mode 100644 index 0000000000..b63b151765 Binary files /dev/null and b/render-test/tests/network/fail-transferred/expected.png differ diff --git a/render-test/tests/network/fail-transferred/metrics.json b/render-test/tests/network/fail-transferred/metrics.json new file mode 100644 index 0000000000..20b42d5b9b --- /dev/null +++ b/render-test/tests/network/fail-transferred/metrics.json @@ -0,0 +1,14 @@ +{ + "network": [ + [ + "end", + 3, + 100000 + ], + [ + "start", + 0, + 0 + ] + ] +} \ No newline at end of file diff --git a/render-test/tests/network/fail-transferred/style.json b/render-test/tests/network/fail-transferred/style.json new file mode 100644 index 0000000000..ef94ddc748 --- /dev/null +++ b/render-test/tests/network/fail-transferred/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeNetworkStart"], + ["probeNetwork", "start"], + ["wait"], + ["probeNetwork", "end"], + ["probeNetworkEnd"] + ], + "height": 256, + "width": 1024 + } + }, + "center": [ + -73, + 15 + ], + "zoom": 4.5, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/mapbox.mapbox-streets-v7/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line-center", + "type": "symbol", + "source": "mapbox", + "source-layer": "marine_label", + "layout": { + "text-field": "{name_en}", + "symbol-placement": "line-center", + "text-allow-overlap": true, + "text-size": 35, + "text-letter-spacing": 0.4, + "text-offset": [3, 0], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "line", + "type": "line", + "source": "mapbox", + "source-layer": "marine_label", + "paint": { + "line-width": 1 + } + } + ] +} diff --git a/render-test/tests/network/pass/expected.png b/render-test/tests/network/pass/expected.png new file mode 100644 index 0000000000..b63b151765 Binary files /dev/null and b/render-test/tests/network/pass/expected.png differ diff --git a/render-test/tests/network/pass/metrics.json b/render-test/tests/network/pass/metrics.json new file mode 100644 index 0000000000..6afd106a45 --- /dev/null +++ b/render-test/tests/network/pass/metrics.json @@ -0,0 +1,14 @@ +{ + "network": [ + [ + "end", + 3, + 183111 + ], + [ + "start", + 0, + 0 + ] + ] +} \ No newline at end of file diff --git a/render-test/tests/network/pass/style.json b/render-test/tests/network/pass/style.json new file mode 100644 index 0000000000..ef94ddc748 --- /dev/null +++ b/render-test/tests/network/pass/style.json @@ -0,0 +1,67 @@ +{ + "version": 8, + "metadata": { + "test": { + "operations": [ + ["probeNetworkStart"], + ["probeNetwork", "start"], + ["wait"], + ["probeNetwork", "end"], + ["probeNetworkEnd"] + ], + "height": 256, + "width": 1024 + } + }, + "center": [ + -73, + 15 + ], + "zoom": 4.5, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/mapbox.mapbox-streets-v7/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "line-center", + "type": "symbol", + "source": "mapbox", + "source-layer": "marine_label", + "layout": { + "text-field": "{name_en}", + "symbol-placement": "line-center", + "text-allow-overlap": true, + "text-size": 35, + "text-letter-spacing": 0.4, + "text-offset": [3, 0], + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + } + }, + { + "id": "line", + "type": "line", + "source": "mapbox", + "source-layer": "marine_label", + "paint": { + "line-width": 1 + } + } + ] +} diff --git a/render-test/tests/should-fail.json b/render-test/tests/should-fail.json index 30c91836a7..d80b419605 100644 --- a/render-test/tests/should-fail.json +++ b/render-test/tests/should-fail.json @@ -2,5 +2,8 @@ "tests/file-size/fail-size-is-over": "Should fail, size is bigger than expected.", "tests/file-size/fail-size-is-under": "Should fail, size is smaller than expected.", "tests/file-size/fail-file-doesnt-match": "Should fail, doesn't match the expectation.", - "tests/file-size/fail-file-not-found": "Should fail, file not found." + "tests/file-size/fail-file-not-found": "Should fail, file not found.", + "tests/network/fail-requests": "Should fail, number of requests higher than expected.", + "tests/network/fail-transferred": "Should fail, amount of transferred data higher than expected.", + "tests/network/fail-requests-transferred": "Should fail, number of requests higher than expected and amount of transferred data less than expected." } -- cgit v1.2.1 From a8558379dbbc92ca75c9c3057990ac6c78a06e1f Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Thu, 8 Aug 2019 17:15:25 +0300 Subject: [android] Check flag before runnable task invocation --- platform/android/src/async_task.cpp | 9 ++++++--- platform/android/src/timer.cpp | 12 +++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/platform/android/src/async_task.cpp b/platform/android/src/async_task.cpp index 6c14e96fa6..0a4d90a275 100644 --- a/platform/android/src/async_task.cpp +++ b/platform/android/src/async_task.cpp @@ -16,6 +16,7 @@ public: } ~Impl() { + queued = true; loop->removeRunnable(this); } @@ -31,9 +32,11 @@ public: } void runTask() override { - loop->removeRunnable(this); - queued = true; - task(); + if (!queued) { + queued = true; + loop->removeRunnable(this); + task(); + } } private: diff --git a/platform/android/src/timer.cpp b/platform/android/src/timer.cpp index a45c48702e..1d3d05c843 100644 --- a/platform/android/src/timer.cpp +++ b/platform/android/src/timer.cpp @@ -3,6 +3,7 @@ #include #include +#include #include namespace mbgl { @@ -10,7 +11,7 @@ namespace util { class Timer::Impl : public RunLoop::Impl::Runnable { public: - Impl() = default; + Impl() : active(false) {} ~Impl() { stop(); @@ -25,9 +26,11 @@ public: due = (timeout == Duration::max()) ? std::chrono::time_point::max() : Clock::now() + timeout; loop->addRunnable(this); + active = true; } void stop() { + active = false; loop->removeRunnable(this); } @@ -45,8 +48,10 @@ public: } void runTask() override { - reschedule(); - task(); + if (active) { + reschedule(); + task(); + } } private: @@ -56,6 +61,7 @@ private: RunLoop::Impl* loop = reinterpret_cast(RunLoop::getLoopHandle()); std::function task; + std::atomic active; }; Timer::Timer() : impl(std::make_unique()) { -- cgit v1.2.1 From 057048b293d00aed6fc964109e3bfa6bc5ba39ed Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 17 Oct 2019 15:13:30 +0300 Subject: [core] Fix image requests for already obtained images Before this change, repeated request for an already obtained image was erroneously treated as pending. --- src/mbgl/renderer/image_manager.cpp | 9 ++++++--- src/mbgl/renderer/image_manager.hpp | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 0920f5a659..7b51fb9a2e 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -189,9 +189,12 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR auto existingRequestorsIt = requestedImages.find(missingImage); if (existingRequestorsIt != requestedImages.end()) { // Already asked client about this image. - if (!existingRequestorsIt->second.empty()) { // Still waiting for the client response. - existingRequestorsIt->second.emplace(requestorPtr); - requestor.addPendingRequest(missingImage); + std::set& existingRequestors = existingRequestorsIt->second; + if (!existingRequestors.empty() && + (*existingRequestors.begin()) + ->hasPendingRequest(missingImage)) { // Still waiting for the client response for this image. + requestorPtr->addPendingRequest(missingImage); + existingRequestors.emplace(requestorPtr); continue; } // Unlike icons, pattern changes are not caught diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index 98b42da838..5ed6e237f0 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -73,9 +73,8 @@ public: virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) = 0; void addPendingRequest(const std::string& imageId) { pendingRequests.insert(imageId); } - + bool hasPendingRequest(const std::string& imageId) const { return pendingRequests.count(imageId); } bool hasPendingRequests() const { return !pendingRequests.empty(); } - void removePendingRequest(const std::string& imageId) { pendingRequests.erase(imageId); } private: -- cgit v1.2.1 From 3ac706edfefc9c8f2ee1ad9eb38bf688364cdb77 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 17 Oct 2019 15:42:30 +0300 Subject: [core] Update ImageManager.OnStyleImageMissingBeforeSpriteLoaded So that it checks pending image requests for a different requestor. --- test/renderer/image_manager.test.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp index f1061ce59e..20c0a3a7f3 100644 --- a/test/renderer/image_manager.test.cpp +++ b/test/renderer/image_manager.test.cpp @@ -189,7 +189,7 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) { // Repeated request of the same image shall not result another // `ImageManagerObserver.onStyleImageMissing()` call. - imageManager.getImages(requestor, std::make_pair(dependencies, imageCorrelationID)); + imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); runLoop.runOnce(); EXPECT_EQ(observer.count, 1); @@ -197,10 +197,20 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) { // Request for updated dependencies must be dispatched to the // observer. dependencies.emplace("post", ImageType::Icon); - imageManager.getImages(requestor, std::make_pair(dependencies, imageCorrelationID)); + imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); runLoop.runOnce(); EXPECT_EQ(observer.count, 2); + + // Another requestor shall not have pending requests for already obtained images. + StubImageRequestor anotherRequestor(imageManager); + imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID)); + ASSERT_FALSE(anotherRequestor.hasPendingRequests()); + + dependencies.emplace("unfamiliar", ImageType::Icon); + imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID)); + EXPECT_TRUE(anotherRequestor.hasPendingRequests()); + EXPECT_TRUE(anotherRequestor.hasPendingRequest("unfamiliar")); } TEST(ImageManager, OnStyleImageMissingAfterSpriteLoaded) { -- cgit v1.2.1 From 722a0c2f616e4094996c39c42335dc47e1c1f87a Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 15 Oct 2019 18:06:31 +0300 Subject: [build] Make output of the tests verbose We have a flaky test that is hanging on the bots and we need to find out which one. --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index b45a623866..e1923498a7 100644 --- a/circle.yml +++ b/circle.yml @@ -280,7 +280,7 @@ commands: name: Test command: | cd build - << parameters.test_wrapper >> ctest --output-on-failure << parameters.test_params >> + << parameters.test_wrapper >> ctest -V << parameters.test_params >> npm-install: steps: - run: -- cgit v1.2.1 From bbeb86577eea34d6241f0e70119f91f208cd7a12 Mon Sep 17 00:00:00 2001 From: Fabian Guerra Soto Date: Fri, 18 Oct 2019 13:59:04 -0700 Subject: [ios] Add ARC config to the new build system. (#15833) --- next/platform/ios/ios.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/next/platform/ios/ios.cmake b/next/platform/ios/ios.cmake index 7a729d996a..135a637783 100644 --- a/next/platform/ios/ios.cmake +++ b/next/platform/ios/ios.cmake @@ -3,6 +3,8 @@ target_compile_definitions( PUBLIC MBGL_USE_GLES2 GLES_SILENCE_DEPRECATION ) +set_target_properties(mbgl-core PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) + target_sources( mbgl-core PRIVATE -- cgit v1.2.1 From f41f274ca16032da8c41186b2181f0c800d777df Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Sat, 19 Oct 2019 23:04:52 +0300 Subject: [build] Only add mapbox-base if target is not set --- next/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index fb0779bea4..c45c2b8641 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -877,8 +877,10 @@ target_include_directories( PUBLIC ${MBGL_ROOT}/include ) -add_subdirectory(${PROJECT_SOURCE_DIR}/vendor/mapbox-base/mapbox) -add_subdirectory(${PROJECT_SOURCE_DIR}/vendor/mapbox-base/extras) +if(NOT TARGET mapbox-base) + add_subdirectory(${PROJECT_SOURCE_DIR}/vendor/mapbox-base/mapbox) + add_subdirectory(${PROJECT_SOURCE_DIR}/vendor/mapbox-base/extras) +endif(NOT TARGET mapbox-base) include(${PROJECT_SOURCE_DIR}/vendor/boost.cmake) include(${PROJECT_SOURCE_DIR}/vendor/earcut.hpp.cmake) -- cgit v1.2.1 From 9adc78134c261d5e236faac3b537e1cfd937880a Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 11 Oct 2019 10:43:02 +0300 Subject: [test runner] Threshold for memory metrics --- render-test/metadata.hpp | 13 ++++++++++--- render-test/parser.cpp | 2 +- render-test/runner.cpp | 28 +++++++++++++++++++--------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index c26fde1d19..20cc440fd4 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -49,12 +49,19 @@ struct FileSizeProbe { struct MemoryProbe { MemoryProbe() = default; - MemoryProbe(size_t peak_, size_t allocations_) - : peak(peak_) - , allocations(allocations_) {} + MemoryProbe(size_t peak_, size_t allocations_) : peak(peak_), allocations(allocations_), tolerance(0.0f) {} size_t peak; size_t allocations; + float tolerance; + + static std::tuple checkPeak(const MemoryProbe& expected, const MemoryProbe& actual) { + return checkValue(expected.peak, actual.peak, actual.tolerance); + } + + static std::tuple checkAllocations(const MemoryProbe& expected, const MemoryProbe& actual) { + return checkValue(expected.allocations, actual.allocations, actual.tolerance); + } }; struct NetworkProbe { diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 41c9b83298..7300530b07 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -507,7 +507,7 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { assert(probeValue[1].IsNumber()); assert(probeValue[2].IsNumber()); - const std::string mark { probeValue[0].GetString(), probeValue[0].GetStringLength() }; + std::string mark{probeValue[0].GetString(), probeValue[0].GetStringLength()}; assert(!mark.empty()); result.memory.emplace(std::piecewise_construct, std::forward_as_tuple(std::move(mark)), diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 810806d231..925599dfb8 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -276,19 +276,23 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, metadata.errorMessage = "Failed to find memory probe: " + expected.first; return false; } - if (actual->second.peak > expected.second.peak) { + bool passed{false}; + float delta{0.0f}; + std::tie(passed, delta) = MemoryProbe::checkPeak(expected.second, actual->second); + if (!passed) { std::stringstream ss; - ss << "Allocated memory peak size at probe \"" << expected.first << "\" is " - << actual->second.peak << " bytes, expected is " << expected.second.peak << " bytes."; + ss << "Allocated memory peak size at probe \"" << expected.first << "\" is " << actual->second.peak + << " bytes, expected is " << expected.second.peak << "±" << delta << " bytes."; metadata.errorMessage = ss.str(); return false; } - if (actual->second.allocations > expected.second.allocations) { + std::tie(passed, delta) = MemoryProbe::checkAllocations(expected.second, actual->second); + if (!passed) { std::stringstream ss; - ss << "Number of allocations at probe \"" << expected.first << "\" is " - << actual->second.allocations << ", expected is " << expected.second.allocations << "."; + ss << "Number of allocations at probe \"" << expected.first << "\" is " << actual->second.allocations + << ", expected is " << expected.second.allocations << "±" << delta << " allocations."; metadata.errorMessage = ss.str(); return false; @@ -644,9 +648,15 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(operationArray[1].IsString()); std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength()); - metadata.metrics.memory.emplace(std::piecewise_construct, - std::forward_as_tuple(std::move(mark)), - std::forward_as_tuple(AllocationIndex::getAllocatedSizePeak(), AllocationIndex::getAllocationsCount())); + auto emplaced = metadata.metrics.memory.emplace( + std::piecewise_construct, + std::forward_as_tuple(std::move(mark)), + std::forward_as_tuple(AllocationIndex::getAllocatedSizePeak(), AllocationIndex::getAllocationsCount())); + assert(emplaced.second); + if (operationArray.Size() >= 3u) { + assert(operationArray[2].IsNumber()); + emplaced.first->second.tolerance = float(operationArray[2].GetDouble()); + } } else if (operationArray[0].GetString() == memoryProbeEndOp) { // probeMemoryEnd assert(AllocationIndex::isActive()); -- cgit v1.2.1 From b0976feca26769261ee824688d6fae78298ae0da Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 11 Oct 2019 14:06:02 +0300 Subject: [test runner] Tests for memory size metrics --- render-test/runner.cpp | 2 +- .../fail-memory-size-is-too-big/expected.png | Bin 0 -> 96 bytes .../fail-memory-size-is-too-big/metrics.json | 1 + .../memory/fail-memory-size-is-too-big/style.json | 52 +++++++++++++++++++++ .../fail-memory-size-is-too-small/expected.png | Bin 0 -> 96 bytes .../fail-memory-size-is-too-small/metrics.json | 1 + .../fail-memory-size-is-too-small/style.json | 52 +++++++++++++++++++++ .../memory/pass-memory-size-is-same/expected.png | Bin 0 -> 96 bytes .../memory/pass-memory-size-is-same/metrics.json | 1 + .../memory/pass-memory-size-is-same/style.json | 52 +++++++++++++++++++++ render-test/tests/should-fail.json | 4 +- 11 files changed, 163 insertions(+), 2 deletions(-) create mode 100644 render-test/tests/memory/fail-memory-size-is-too-big/expected.png create mode 100644 render-test/tests/memory/fail-memory-size-is-too-big/metrics.json create mode 100644 render-test/tests/memory/fail-memory-size-is-too-big/style.json create mode 100644 render-test/tests/memory/fail-memory-size-is-too-small/expected.png create mode 100644 render-test/tests/memory/fail-memory-size-is-too-small/metrics.json create mode 100644 render-test/tests/memory/fail-memory-size-is-too-small/style.json create mode 100644 render-test/tests/memory/pass-memory-size-is-same/expected.png create mode 100644 render-test/tests/memory/pass-memory-size-is-same/metrics.json create mode 100644 render-test/tests/memory/pass-memory-size-is-same/style.json diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 925599dfb8..401b060fd6 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -292,7 +292,7 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, if (!passed) { std::stringstream ss; ss << "Number of allocations at probe \"" << expected.first << "\" is " << actual->second.allocations - << ", expected is " << expected.second.allocations << "±" << delta << " allocations."; + << ", expected is " << expected.second.allocations << "±" << std::round(delta) << " allocations."; metadata.errorMessage = ss.str(); return false; diff --git a/render-test/tests/memory/fail-memory-size-is-too-big/expected.png b/render-test/tests/memory/fail-memory-size-is-too-big/expected.png new file mode 100644 index 0000000000..0858c19f05 Binary files /dev/null and b/render-test/tests/memory/fail-memory-size-is-too-big/expected.png differ diff --git a/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json b/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json new file mode 100644 index 0000000000..69832a1d9f --- /dev/null +++ b/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json @@ -0,0 +1 @@ +{"memory":[["after setZoom 0.9",33271,62],["end",40000,118],["start",0,0]]} diff --git a/render-test/tests/memory/fail-memory-size-is-too-big/style.json b/render-test/tests/memory/fail-memory-size-is-too-big/style.json new file mode 100644 index 0000000000..b2805ef34f --- /dev/null +++ b/render-test/tests/memory/fail-memory-size-is-too-big/style.json @@ -0,0 +1,52 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 64, + "height": 64, + "operations": [ + [ "wait" ], + [ "probeMemoryStart" ], + [ "probeMemory", "start" ], + [ + "setZoom", + 0.9 + ], + [ + "wait" + ], + [ "probeMemory", "after setZoom 0.9", 0.005 ], + [ + "setLayerZoomRange", + "circle", + 1, + 2 + ], + [ + "wait" + ], + [ "probeMemory", "end", 0.005 ], + [ "probeMemoryEnd" ] + ] + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/memory/fail-memory-size-is-too-small/expected.png b/render-test/tests/memory/fail-memory-size-is-too-small/expected.png new file mode 100644 index 0000000000..0858c19f05 Binary files /dev/null and b/render-test/tests/memory/fail-memory-size-is-too-small/expected.png differ diff --git a/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json b/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json new file mode 100644 index 0000000000..51cdc6267c --- /dev/null +++ b/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json @@ -0,0 +1 @@ +{"memory":[["after setZoom 0.9",33271,62],["end",60000,118],["start",0,0]]} diff --git a/render-test/tests/memory/fail-memory-size-is-too-small/style.json b/render-test/tests/memory/fail-memory-size-is-too-small/style.json new file mode 100644 index 0000000000..b2805ef34f --- /dev/null +++ b/render-test/tests/memory/fail-memory-size-is-too-small/style.json @@ -0,0 +1,52 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 64, + "height": 64, + "operations": [ + [ "wait" ], + [ "probeMemoryStart" ], + [ "probeMemory", "start" ], + [ + "setZoom", + 0.9 + ], + [ + "wait" + ], + [ "probeMemory", "after setZoom 0.9", 0.005 ], + [ + "setLayerZoomRange", + "circle", + 1, + 2 + ], + [ + "wait" + ], + [ "probeMemory", "end", 0.005 ], + [ "probeMemoryEnd" ] + ] + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/memory/pass-memory-size-is-same/expected.png b/render-test/tests/memory/pass-memory-size-is-same/expected.png new file mode 100644 index 0000000000..0858c19f05 Binary files /dev/null and b/render-test/tests/memory/pass-memory-size-is-same/expected.png differ diff --git a/render-test/tests/memory/pass-memory-size-is-same/metrics.json b/render-test/tests/memory/pass-memory-size-is-same/metrics.json new file mode 100644 index 0000000000..9ed24a99c7 --- /dev/null +++ b/render-test/tests/memory/pass-memory-size-is-same/metrics.json @@ -0,0 +1 @@ +{"memory":[["after setZoom 0.9",33271,62],["end",47833,118],["start",0,0]]} \ No newline at end of file diff --git a/render-test/tests/memory/pass-memory-size-is-same/style.json b/render-test/tests/memory/pass-memory-size-is-same/style.json new file mode 100644 index 0000000000..b2805ef34f --- /dev/null +++ b/render-test/tests/memory/pass-memory-size-is-same/style.json @@ -0,0 +1,52 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 64, + "height": 64, + "operations": [ + [ "wait" ], + [ "probeMemoryStart" ], + [ "probeMemory", "start" ], + [ + "setZoom", + 0.9 + ], + [ + "wait" + ], + [ "probeMemory", "after setZoom 0.9", 0.005 ], + [ + "setLayerZoomRange", + "circle", + 1, + 2 + ], + [ + "wait" + ], + [ "probeMemory", "end", 0.005 ], + [ "probeMemoryEnd" ] + ] + } + }, + "sources": { + "geojson": { + "type": "geojson", + "data": { + "type": "Point", + "coordinates": [ + 0, + 0 + ] + } + } + }, + "layers": [ + { + "id": "circle", + "type": "circle", + "source": "geojson" + } + ] +} diff --git a/render-test/tests/should-fail.json b/render-test/tests/should-fail.json index d80b419605..f08497b07f 100644 --- a/render-test/tests/should-fail.json +++ b/render-test/tests/should-fail.json @@ -5,5 +5,7 @@ "tests/file-size/fail-file-not-found": "Should fail, file not found.", "tests/network/fail-requests": "Should fail, number of requests higher than expected.", "tests/network/fail-transferred": "Should fail, amount of transferred data higher than expected.", - "tests/network/fail-requests-transferred": "Should fail, number of requests higher than expected and amount of transferred data less than expected." + "tests/network/fail-requests-transferred": "Should fail, number of requests higher than expected and amount of transferred data less than expected.", + "tests/memory/fail-memory-size-is-too-big": "Should fail, memory size is bigger than expected.", + "tests/memory/fail-memory-size-is-too-small": "Should fail, memory size is smaller than expected." } -- cgit v1.2.1 From 8bdd8ec67058b0290d56d4b0b6b01ab84e4c2006 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 11 Oct 2019 14:33:52 +0300 Subject: [test runner] Disable memory metrics checks on sanitize builds --- render-test/runner.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 401b060fd6..651361994a 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -269,6 +269,7 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, return false; } } +#if !defined(SANITIZE) // Check memory metrics. for (const auto& expected : metadata.expectedMetrics.memory) { auto actual = metadata.metrics.memory.find(expected.first); @@ -327,7 +328,7 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, return false; } } - +#endif // !defined(SANITIZE) return true; } -- cgit v1.2.1 From eb3c203d4ed65a91b818c42876bf2f23784aa9c5 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 11 Oct 2019 15:51:11 +0300 Subject: [test runner] Adjust memory metrics test results --- render-test/render_test.cpp | 3 +++ .../memory/fail-memory-size-is-too-big/metrics.json | 20 +++++++++++++++++++- .../fail-memory-size-is-too-small/metrics.json | 20 +++++++++++++++++++- .../memory/pass-memory-size-is-same/metrics.json | 20 +++++++++++++++++++- .../tests/memory/pass-memory-size-is-same/style.json | 4 ++-- 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index bac193237d..ac54d08ca0 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -125,6 +125,9 @@ int runRenderTests(int argc, char** argv) { color = "red"; stats.erroredTests++; printf(ANSI_COLOR_RED "* errored %s" ANSI_COLOR_RESET "\n", id.c_str()); + if (!metadata.errorMessage.empty()) { + printf(ANSI_COLOR_RED "* error: %s" ANSI_COLOR_RESET "\n", metadata.errorMessage.c_str()); + } } else { status = "failed"; color = "red"; diff --git a/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json b/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json index 69832a1d9f..3e55e0c60e 100644 --- a/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json +++ b/render-test/tests/memory/fail-memory-size-is-too-big/metrics.json @@ -1 +1,19 @@ -{"memory":[["after setZoom 0.9",33271,62],["end",40000,118],["start",0,0]]} +{ + "memory": [ + [ + "after setZoom 0.9", + 33271, + 62 + ], + [ + "end", + 40000, + 118 + ], + [ + "start", + 0, + 0 + ] + ] +} diff --git a/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json b/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json index 51cdc6267c..7e3997675b 100644 --- a/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json +++ b/render-test/tests/memory/fail-memory-size-is-too-small/metrics.json @@ -1 +1,19 @@ -{"memory":[["after setZoom 0.9",33271,62],["end",60000,118],["start",0,0]]} +{ + "memory": [ + [ + "after setZoom 0.9", + 33271, + 62 + ], + [ + "end", + 60000, + 118 + ], + [ + "start", + 0, + 0 + ] + ] +} diff --git a/render-test/tests/memory/pass-memory-size-is-same/metrics.json b/render-test/tests/memory/pass-memory-size-is-same/metrics.json index 9ed24a99c7..4baa38c7f7 100644 --- a/render-test/tests/memory/pass-memory-size-is-same/metrics.json +++ b/render-test/tests/memory/pass-memory-size-is-same/metrics.json @@ -1 +1,19 @@ -{"memory":[["after setZoom 0.9",33271,62],["end",47833,118],["start",0,0]]} \ No newline at end of file +{ + "memory": [ + [ + "after setZoom 0.9", + 33271, + 62 + ], + [ + "end", + 47833, + 118 + ], + [ + "start", + 0, + 0 + ] + ] +} \ No newline at end of file diff --git a/render-test/tests/memory/pass-memory-size-is-same/style.json b/render-test/tests/memory/pass-memory-size-is-same/style.json index b2805ef34f..d1c09f69f9 100644 --- a/render-test/tests/memory/pass-memory-size-is-same/style.json +++ b/render-test/tests/memory/pass-memory-size-is-same/style.json @@ -15,7 +15,7 @@ [ "wait" ], - [ "probeMemory", "after setZoom 0.9", 0.005 ], + [ "probeMemory", "after setZoom 0.9", 0.01 ], [ "setLayerZoomRange", "circle", @@ -25,7 +25,7 @@ [ "wait" ], - [ "probeMemory", "end", 0.005 ], + [ "probeMemory", "end", 0.01 ], [ "probeMemoryEnd" ] ] } -- cgit v1.2.1 From b03982730e6c02dcc166a609bf4b8fd17b3cf01d Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 17 Oct 2019 20:13:45 +0300 Subject: [test runner] Command line option for the tests expectations path -e[expectationsPath], --expectationsPath=[expectationsPath] Test expectations path. --- next/platform/linux/linux.cmake | 1 + next/platform/macos/macos.cmake | 1 + render-test/metadata.hpp | 4 ++++ render-test/parser.cpp | 53 ++++++++++++++++++++++++++--------------- render-test/runner.cpp | 9 ------- render-test/runner.hpp | 2 -- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index be905c204f..7b77e134ea 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -143,6 +143,7 @@ add_test( render-tests --recycle-map --shuffle + --expectationsPath=render-test/expected/render-tests --seed=${MBGL_RENDER_TEST_SEED} WORKING_DIRECTORY ${MBGL_ROOT} ) diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index cbe386a1ac..69f41027c6 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -207,6 +207,7 @@ add_test( render-tests --recycle-map --shuffle + --expectationsPath=render-test/expected/render-tests --seed=${MBGL_RENDER_TEST_SEED} WORKING_DIRECTORY ${MBGL_ROOT} ) diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index 20cc440fd4..1d5a346f22 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -22,6 +22,10 @@ struct TestStatistics { }; struct TestPaths { + TestPaths() = default; + TestPaths(mbgl::filesystem::path stylePath_, std::vector expectations_) + : stylePath(std::move(stylePath_)), expectations(std::move(expectations_)) {} + mbgl::filesystem::path stylePath; std::vector expectations; diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 7300530b07..da5e6bea81 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -168,22 +168,6 @@ mbgl::optional localizeMapboxTilesetURL(const std::string& url) { return getIntegrationPath(url, "tilesets/", regex); } -TestPaths makeTestPaths(mbgl::filesystem::path stylePath) { - std::vector expectations{ stylePath }; - expectations.front().remove_filename(); - - const static std::regex regex{ TestRunner::getBasePath() }; - for (const std::string& path : TestRunner::getPlatformExpectationsPaths()) { - expectations.emplace_back(std::regex_replace(expectations.front().string(), regex, path)); - assert(!expectations.back().empty()); - } - - return { - std::move(stylePath), - std::move(expectations) - }; -} - void writeJSON(rapidjson::PrettyWriter& writer, const mbgl::Value& value) { value.match([&writer](const mbgl::NullValue&) { writer.Null(); }, [&writer](bool b) { writer.Bool(b); }, @@ -349,6 +333,25 @@ std::vector readExpectedJSONEntries(const mbgl::filesystem::path& b return readExpectedEntries(regex, base); } +namespace { + +std::vector getTestExpectations(mbgl::filesystem::path testPath, + const mbgl::filesystem::path& testsRootPath, + std::vector expectationsPaths) { + std::vector expectations{std::move(testPath.remove_filename())}; + const auto& defaultTestExpectationsPath = expectations.front().string(); + + const std::regex regex{testsRootPath.string()}; + for (const auto& path : expectationsPaths) { + expectations.emplace_back(std::regex_replace(defaultTestExpectationsPath, regex, path.string())); + assert(!expectations.back().empty()); + } + + return expectations; +} + +} // namespace + ArgumentsTuple parseArguments(int argc, char** argv) { args::ArgumentParser argumentParser("Mapbox GL Test Runner"); @@ -362,8 +365,9 @@ ArgumentsTuple parseArguments(int argc, char** argv) { { "seed" }); args::ValueFlag testPathValue(argumentParser, "rootPath", "Test root rootPath", { 'p', "rootPath" }); - args::ValueFlag testFilterValue(argumentParser, "filter", "Test filter regex", - { 'f', "filter" }); + args::ValueFlag testFilterValue(argumentParser, "filter", "Test filter regex", {'f', "filter"}); + args::ValueFlag expectationsPathValue( + argumentParser, "expectationsPath", "Test expectations path", {'e', "expectationsPath"}); args::PositionalList testNameValues(argumentParser, "URL", "Test name(s)"); try { @@ -395,6 +399,17 @@ ArgumentsTuple parseArguments(int argc, char** argv) { mbgl::Log::Error(mbgl::Event::General, "Provided rootPath '%s' does not exist.", rootPath.string().c_str()); exit(4); } + std::vector expectationsPaths; + if (expectationsPathValue) { + auto expectationsPath = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH) / args::get(expectationsPathValue); + if (!mbgl::filesystem::exists(expectationsPath)) { + mbgl::Log::Error(mbgl::Event::General, + "Provided expectationsPath '%s' does not exist.", + expectationsPath.string().c_str()); + exit(5); + } + expectationsPaths.emplace_back(std::move(expectationsPath)); + } std::vector paths; for (const auto& id : args::get(testNameValues)) { @@ -419,7 +434,7 @@ ArgumentsTuple parseArguments(int argc, char** argv) { continue; } if (testPath.path().filename() == "style.json") { - testPaths.emplace_back(makeTestPaths(testPath)); + testPaths.emplace_back(testPath, getTestExpectations(testPath, path, expectationsPaths)); } } } diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 651361994a..0464fd861a 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -39,15 +39,6 @@ const std::string& TestRunner::getBasePath() { return result; } -// static -const std::vector& TestRunner::getPlatformExpectationsPaths() { - // TODO: Populate from command line. - const static std::vector result { - std::string(TEST_RUNNER_ROOT_PATH).append("/render-test/expected") - }; - return result; -} - std::string simpleDiff(const Value& result, const Value& expected) { std::vector resultTokens{tokenize(toJSON(result, 2, false))}; std::vector expectedTokens{tokenize(toJSON(expected, 2, false))}; diff --git a/render-test/runner.hpp b/render-test/runner.hpp index d8e5275f61..ea593bcc61 100644 --- a/render-test/runner.hpp +++ b/render-test/runner.hpp @@ -16,8 +16,6 @@ public: /// Returns path of the render tests root directory. static const std::string& getBasePath(); - /// Returns path of mapbox-gl-native expectations directory. - static const std::vector& getPlatformExpectationsPaths(); private: bool runOperations(const std::string& key, TestMetadata&); -- cgit v1.2.1 From 61d1018087ff2dc40922eedbe3aac09e2f721c03 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 18 Oct 2019 14:27:53 +0300 Subject: [test runner] Memory metrics expectations for MAC --- next/platform/macos/macos.cmake | 11 ++++++++++- .../mac/memory/pass-memory-size-is-same/expected.png | Bin 0 -> 96 bytes .../mac/memory/pass-memory-size-is-same/metrics.json | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 render-test/tests/mac/memory/pass-memory-size-is-same/expected.png create mode 100644 render-test/tests/mac/memory/pass-memory-size-is-same/metrics.json diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index 69f41027c6..d36b89ac6b 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -212,5 +212,14 @@ add_test( WORKING_DIRECTORY ${MBGL_ROOT} ) -add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test-runner tests --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT}) +add_test( + NAME mbgl-render-test-probes + COMMAND + mbgl-render-test-runner + tests + --rootPath=render-test + --expectationsPath=render-test/tests/mac + WORKING_DIRECTORY ${MBGL_ROOT} +) + add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests WORKING_DIRECTORY ${MBGL_ROOT}) diff --git a/render-test/tests/mac/memory/pass-memory-size-is-same/expected.png b/render-test/tests/mac/memory/pass-memory-size-is-same/expected.png new file mode 100644 index 0000000000..0858c19f05 Binary files /dev/null and b/render-test/tests/mac/memory/pass-memory-size-is-same/expected.png differ diff --git a/render-test/tests/mac/memory/pass-memory-size-is-same/metrics.json b/render-test/tests/mac/memory/pass-memory-size-is-same/metrics.json new file mode 100644 index 0000000000..cc7d1c9fab --- /dev/null +++ b/render-test/tests/mac/memory/pass-memory-size-is-same/metrics.json @@ -0,0 +1,19 @@ +{ + "memory": [ + [ + "after setZoom 0.9", + 33271, + 51 + ], + [ + "end", + 47552, + 101 + ], + [ + "start", + 0, + 0 + ] + ] +} -- cgit v1.2.1 From bb0e5ffb2ceea28d386a9ac317ab9e1e81d83b07 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 21 Oct 2019 15:32:50 +0300 Subject: [test runner] Improve error messaging for memory metrics tests --- render-test/render_test.cpp | 4 +--- render-test/runner.cpp | 21 +++++++++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index ac54d08ca0..c3a9c6dd77 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -125,9 +125,7 @@ int runRenderTests(int argc, char** argv) { color = "red"; stats.erroredTests++; printf(ANSI_COLOR_RED "* errored %s" ANSI_COLOR_RESET "\n", id.c_str()); - if (!metadata.errorMessage.empty()) { - printf(ANSI_COLOR_RED "* error: %s" ANSI_COLOR_RESET "\n", metadata.errorMessage.c_str()); - } + printf(ANSI_COLOR_RED "* error: %s" ANSI_COLOR_RESET "\n", metadata.errorMessage.c_str()); } else { status = "failed"; color = "red"; diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 0464fd861a..1204c72d71 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -270,25 +270,22 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, } bool passed{false}; float delta{0.0f}; + std::stringstream errorStream; std::tie(passed, delta) = MemoryProbe::checkPeak(expected.second, actual->second); if (!passed) { - std::stringstream ss; - ss << "Allocated memory peak size at probe \"" << expected.first << "\" is " << actual->second.peak - << " bytes, expected is " << expected.second.peak << "±" << delta << " bytes."; - - metadata.errorMessage = ss.str(); - return false; + errorStream << "Allocated memory peak size at probe \"" << expected.first << "\" is " << actual->second.peak + << " bytes, expected is " << expected.second.peak << "±" << delta << " bytes."; } std::tie(passed, delta) = MemoryProbe::checkAllocations(expected.second, actual->second); if (!passed) { - std::stringstream ss; - ss << "Number of allocations at probe \"" << expected.first << "\" is " << actual->second.allocations - << ", expected is " << expected.second.allocations << "±" << std::round(delta) << " allocations."; - - metadata.errorMessage = ss.str(); - return false; + errorStream << "Number of allocations at probe \"" << expected.first << "\" is " + << actual->second.allocations << ", expected is " << expected.second.allocations << "±" + << std::round(delta) << " allocations."; } + + metadata.errorMessage = errorStream.str(); + if (!metadata.errorMessage.empty()) return false; } // Check network metrics. -- cgit v1.2.1 From 0ca96fd8a402ae530da72e3955196007a2ec365f Mon Sep 17 00:00:00 2001 From: Mikko Pulkki <55925868+mpulkki-mapbox@users.noreply.github.com> Date: Tue, 22 Oct 2019 12:13:55 +0300 Subject: [render-test] Implement fps benchmarking tests (#15803) --- include/mbgl/util/monotonic_timer.hpp | 24 ++ next/platform/android/android.cmake | 1 + next/platform/ios/ios.cmake | 1 + next/platform/linux/linux.cmake | 1 + next/platform/macos/macos.cmake | 1 + next/platform/qt/qt.cmake | 1 + platform/android/core-files.json | 1 + .../default/include/mbgl/gfx/headless_backend.hpp | 10 +- .../default/include/mbgl/gfx/headless_frontend.hpp | 8 +- .../default/include/mbgl/gl/headless_backend.hpp | 7 +- .../default/src/mbgl/gfx/headless_frontend.cpp | 61 +++-- platform/default/src/mbgl/gl/headless_backend.cpp | 32 ++- platform/default/src/mbgl/map/map_snapshotter.cpp | 4 +- platform/default/src/mbgl/util/monotonic_timer.cpp | 24 ++ platform/ios/core-files.json | 1 + platform/linux/config.cmake | 1 + platform/macos/core-files.json | 1 + render-test/metadata.hpp | 10 +- render-test/parser.cpp | 77 +++++-- render-test/render_test.cpp | 3 +- render-test/runner.cpp | 256 ++++++++++++++++----- render-test/runner.hpp | 3 + src/core-files.json | 1 + src/mbgl/gl/context.cpp | 4 + src/mbgl/gl/context.hpp | 2 + test/gl/context.test.cpp | 5 +- test/text/local_glyph_rasterizer.test.cpp | 4 +- 27 files changed, 422 insertions(+), 122 deletions(-) create mode 100644 include/mbgl/util/monotonic_timer.hpp create mode 100644 platform/default/src/mbgl/util/monotonic_timer.cpp diff --git a/include/mbgl/util/monotonic_timer.hpp b/include/mbgl/util/monotonic_timer.hpp new file mode 100644 index 0000000000..bdb167214b --- /dev/null +++ b/include/mbgl/util/monotonic_timer.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace util { + +class MonotonicTimer { +public: + static std::chrono::duration now(); + + template + inline static std::chrono::duration duration(F&& func, Args&&... args) { + auto start = now(); + func(std::forward(args)...); + return now() - start; + } +}; + +} // namespace util +} // namespace mbgl \ No newline at end of file diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index 1bde72d11d..6032294ff7 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -213,6 +213,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/bidi.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/util/monotonic_timer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/png_writer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/thread_local.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/utf.cpp diff --git a/next/platform/ios/ios.cmake b/next/platform/ios/ios.cmake index 135a637783..4558b47b68 100644 --- a/next/platform/ios/ios.cmake +++ b/next/platform/ios/ios.cmake @@ -39,6 +39,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/bidi.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/util/monotonic_timer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/png_writer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/thread_local.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/utf.cpp diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 7b77e134ea..6a68a1f2d2 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -37,6 +37,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/util/image.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/jpeg_reader.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/logging_stderr.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/util/monotonic_timer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/png_reader.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/png_writer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/run_loop.cpp diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index d36b89ac6b..71e53c474a 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -105,6 +105,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/text/bidi.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/util/monotonic_timer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/png_writer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/thread_local.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/utf.cpp diff --git a/next/platform/qt/qt.cmake b/next/platform/qt/qt.cmake index b902388565..4fb56176d0 100644 --- a/next/platform/qt/qt.cmake +++ b/next/platform/qt/qt.cmake @@ -43,6 +43,7 @@ target_sources( ${MBGL_ROOT}/platform/default/src/mbgl/storage/online_file_source.cpp ${MBGL_ROOT}/platform/default/src/mbgl/storage/sqlite3.cpp ${MBGL_ROOT}/platform/default/src/mbgl/util/compression.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/util/monotonic_timer.cpp ${MBGL_ROOT}/platform/qt/src/async_task.cpp ${MBGL_ROOT}/platform/qt/src/async_task_impl.hpp ${MBGL_ROOT}/platform/qt/src/number_format.cpp diff --git a/platform/android/core-files.json b/platform/android/core-files.json index d536247154..e21a586e29 100644 --- a/platform/android/core-files.json +++ b/platform/android/core-files.json @@ -93,6 +93,7 @@ "platform/default/src/mbgl/map/map_snapshotter.cpp", "platform/default/src/mbgl/text/bidi.cpp", "platform/default/src/mbgl/util/compression.cpp", + "platform/default/src/mbgl/util/monotonic_timer.cpp", "platform/default/src/mbgl/util/png_writer.cpp", "platform/default/src/mbgl/util/thread_local.cpp", "platform/default/src/mbgl/util/utf.cpp", diff --git a/platform/default/include/mbgl/gfx/headless_backend.hpp b/platform/default/include/mbgl/gfx/headless_backend.hpp index 325422323a..5167e6a465 100644 --- a/platform/default/include/mbgl/gfx/headless_backend.hpp +++ b/platform/default/include/mbgl/gfx/headless_backend.hpp @@ -15,11 +15,13 @@ namespace gfx { // of readStillImage. class HeadlessBackend : public gfx::Renderable { public: + enum class SwapBehaviour { NoFlush, Flush }; + // Factory. - static std::unique_ptr - Create(const Size size = { 256, 256 }, - const gfx::ContextMode contextMode = gfx::ContextMode::Unique) { - return Backend::Create(size, contextMode); + static std::unique_ptr Create(const Size size = {256, 256}, + SwapBehaviour swapBehavior = SwapBehaviour::NoFlush, + const gfx::ContextMode contextMode = gfx::ContextMode::Unique) { + return Backend::Create(size, swapBehavior, contextMode); } virtual PremultipliedImage readStillImage() = 0; diff --git a/platform/default/include/mbgl/gfx/headless_frontend.hpp b/platform/default/include/mbgl/gfx/headless_frontend.hpp index 8f7a7bf202..353452123d 100644 --- a/platform/default/include/mbgl/gfx/headless_frontend.hpp +++ b/platform/default/include/mbgl/gfx/headless_frontend.hpp @@ -1,11 +1,12 @@ #pragma once +#include #include #include -#include #include #include +#include #include namespace mbgl { @@ -17,10 +18,12 @@ class TransformState; class HeadlessFrontend : public RendererFrontend { public: HeadlessFrontend(float pixelRatio_, + gfx::HeadlessBackend::SwapBehaviour swapBehviour = gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode mode = gfx::ContextMode::Unique, const optional localFontFamily = {}); HeadlessFrontend(Size, float pixelRatio_, + gfx::HeadlessBackend::SwapBehaviour swapBehviour = gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode mode = gfx::ContextMode::Unique, const optional localFontFamily = {}); ~HeadlessFrontend() override; @@ -29,6 +32,7 @@ public: void update(std::shared_ptr) override; void setObserver(RendererObserver&) override; + double getFrameTime() const; Size getSize() const; void setSize(Size); @@ -45,6 +49,7 @@ public: PremultipliedImage readStillImage(); PremultipliedImage render(Map&); + void renderOnce(Map&); optional getTransformState() const; @@ -52,6 +57,7 @@ private: Size size; float pixelRatio; + std::atomic frameTime; std::unique_ptr backend; util::AsyncTask asyncInvalidate; diff --git a/platform/default/include/mbgl/gl/headless_backend.hpp b/platform/default/include/mbgl/gl/headless_backend.hpp index 8aefb5ff6c..b77f1b756f 100644 --- a/platform/default/include/mbgl/gl/headless_backend.hpp +++ b/platform/default/include/mbgl/gl/headless_backend.hpp @@ -10,13 +10,17 @@ namespace gl { class HeadlessBackend final : public gl::RendererBackend, public gfx::HeadlessBackend { public: - HeadlessBackend(Size = { 256, 256 }, gfx::ContextMode = gfx::ContextMode::Unique); + HeadlessBackend(Size = {256, 256}, + SwapBehaviour = SwapBehaviour::NoFlush, + gfx::ContextMode = gfx::ContextMode::Unique); ~HeadlessBackend() override; void updateAssumedState() override; gfx::Renderable& getDefaultRenderable() override; PremultipliedImage readStillImage() override; RendererBackend* getRendererBackend() override; + void swap(); + class Impl { public: virtual ~Impl() = default; @@ -37,6 +41,7 @@ private: private: std::unique_ptr impl; bool active = false; + SwapBehaviour swapBehaviour = SwapBehaviour::NoFlush; }; } // namespace gl diff --git a/platform/default/src/mbgl/gfx/headless_frontend.cpp b/platform/default/src/mbgl/gfx/headless_frontend.cpp index 287567adbd..87d09911a2 100644 --- a/platform/default/src/mbgl/gfx/headless_frontend.cpp +++ b/platform/default/src/mbgl/gfx/headless_frontend.cpp @@ -1,43 +1,50 @@ -#include #include +#include +#include +#include #include #include #include -#include -#include +#include #include namespace mbgl { HeadlessFrontend::HeadlessFrontend(float pixelRatio_, + gfx::HeadlessBackend::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode, const optional localFontFamily) - : HeadlessFrontend( - { 256, 256 }, pixelRatio_, contextMode, localFontFamily) { -} + : HeadlessFrontend({256, 256}, pixelRatio_, swapBehavior, contextMode, localFontFamily) {} HeadlessFrontend::HeadlessFrontend(Size size_, float pixelRatio_, + gfx::HeadlessBackend::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode, const optional localFontFamily) : size(size_), pixelRatio(pixelRatio_), - backend(gfx::HeadlessBackend::Create({ static_cast(size.width * pixelRatio), - static_cast(size.height * pixelRatio) }, contextMode)), - asyncInvalidate([this] { - if (renderer && updateParameters) { - gfx::BackendScope guard { *getBackend() }; - - // onStyleImageMissing might be called during a render. The user implemented method - // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`. - // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is - // still using them. - auto updateParameters_ = updateParameters; - renderer->render(*updateParameters_); - } - }), - renderer(std::make_unique(*getBackend(), pixelRatio, localFontFamily)) { -} + frameTime(0), + backend(gfx::HeadlessBackend::Create( + {static_cast(size.width * pixelRatio), static_cast(size.height * pixelRatio)}, + swapBehavior, + contextMode)), + asyncInvalidate([this] { + if (renderer && updateParameters) { + auto startTime = mbgl::util::MonotonicTimer::now(); + gfx::BackendScope guard{*getBackend()}; + + // onStyleImageMissing might be called during a render. The user implemented method + // could trigger a call to MGLRenderFrontend#update which overwrites `updateParameters`. + // Copy the shared pointer here so that the parameters aren't destroyed while `render(...)` is + // still using them. + auto updateParameters_ = updateParameters; + renderer->render(*updateParameters_); + + auto endTime = mbgl::util::MonotonicTimer::now(); + frameTime = (endTime - startTime).count(); + } + }), + renderer(std::make_unique(*getBackend(), pixelRatio, localFontFamily)) {} HeadlessFrontend::~HeadlessFrontend() = default; @@ -56,6 +63,10 @@ void HeadlessFrontend::setObserver(RendererObserver& observer_) { renderer->setObserver(&observer_); } +double HeadlessFrontend::getFrameTime() const { + return frameTime; +} + Size HeadlessFrontend::getSize() const { return size; } @@ -147,10 +158,14 @@ PremultipliedImage HeadlessFrontend::render(Map& map) { if (error) { std::rethrow_exception(error); } - + return result; } +void HeadlessFrontend::renderOnce(Map&) { + util::RunLoop::Get()->runOnce(); +} + optional HeadlessFrontend::getTransformState() const { if (updateParameters) { return updateParameters->transformState; diff --git a/platform/default/src/mbgl/gl/headless_backend.cpp b/platform/default/src/mbgl/gl/headless_backend.cpp index 732e4babae..697c560f76 100644 --- a/platform/default/src/mbgl/gl/headless_backend.cpp +++ b/platform/default/src/mbgl/gl/headless_backend.cpp @@ -12,12 +12,12 @@ namespace gl { class HeadlessRenderableResource final : public gl::RenderableResource { public: - HeadlessRenderableResource(gl::Context& context_, Size size_) - : context(context_), + HeadlessRenderableResource(HeadlessBackend& backend_, gl::Context& context_, Size size_) + : backend(backend_), + context(context_), color(context.createRenderbuffer(size_)), depthStencil(context.createRenderbuffer(size_)), - framebuffer(context.createFramebuffer(color, depthStencil)) { - } + framebuffer(context.createFramebuffer(color, depthStencil)) {} void bind() override { context.bindFramebuffer = framebuffer.framebuffer; @@ -25,18 +25,22 @@ public: context.viewport = { 0, 0, framebuffer.size }; } + void swap() override { backend.swap(); } + + HeadlessBackend& backend; gl::Context& context; gfx::Renderbuffer color; gfx::Renderbuffer depthStencil; gl::Framebuffer framebuffer; }; -HeadlessBackend::HeadlessBackend(const Size size_, const gfx::ContextMode contextMode_) - : mbgl::gl::RendererBackend(contextMode_), mbgl::gfx::HeadlessBackend(size_) { -} +HeadlessBackend::HeadlessBackend(const Size size_, + gfx::HeadlessBackend::SwapBehaviour swapBehaviour_, + const gfx::ContextMode contextMode_) + : mbgl::gl::RendererBackend(contextMode_), mbgl::gfx::HeadlessBackend(size_), swapBehaviour(swapBehaviour_) {} HeadlessBackend::~HeadlessBackend() { - gfx::BackendScope guard { *this }; + gfx::BackendScope guard{*this}; resource.reset(); // Explicitly reset the context so that it is destructed and cleaned up before we destruct // the impl object. @@ -67,11 +71,15 @@ void HeadlessBackend::deactivate() { gfx::Renderable& HeadlessBackend::getDefaultRenderable() { if (!resource) { - resource = std::make_unique(static_cast(getContext()), size); + resource = std::make_unique(*this, static_cast(getContext()), size); } return *this; } +void HeadlessBackend::swap() { + if (swapBehaviour == SwapBehaviour::Flush) static_cast(getContext()).finish(); +} + void HeadlessBackend::updateAssumedState() { // no-op } @@ -89,9 +97,9 @@ RendererBackend* HeadlessBackend::getRendererBackend() { namespace gfx { template <> -std::unique_ptr -Backend::Create(const Size size, const gfx::ContextMode contextMode) { - return std::make_unique(size, contextMode); +std::unique_ptr Backend::Create( + const Size size, gfx::HeadlessBackend::SwapBehaviour swapBehavior, const gfx::ContextMode contextMode) { + return std::make_unique(size, swapBehavior, contextMode); } } // namespace gfx diff --git a/platform/default/src/mbgl/map/map_snapshotter.cpp b/platform/default/src/mbgl/map/map_snapshotter.cpp index 5f4060e3f0..705a791af9 100644 --- a/platform/default/src/mbgl/map/map_snapshotter.cpp +++ b/platform/default/src/mbgl/map/map_snapshotter.cpp @@ -51,8 +51,8 @@ MapSnapshotter::Impl::Impl(const std::pair style, const optional region, const optional localFontFamily, const ResourceOptions& resourceOptions) - : frontend( - size, pixelRatio, gfx::ContextMode::Unique, localFontFamily), + : frontend( + size, pixelRatio, gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode::Unique, localFontFamily), map(frontend, MapObserver::nullObserver(), MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio), diff --git a/platform/default/src/mbgl/util/monotonic_timer.cpp b/platform/default/src/mbgl/util/monotonic_timer.cpp new file mode 100644 index 0000000000..43c2ce6717 --- /dev/null +++ b/platform/default/src/mbgl/util/monotonic_timer.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +namespace mbgl { +namespace util { + +// Prefer high resolution timer if it is monotonic +template * = nullptr> +static T sample() { + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()); +} + +template * = nullptr> +static T sample() { + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()); +} + +std::chrono::duration MonotonicTimer::now() { + return sample>(); +} + +} // namespace util +} // namespace mbgl \ No newline at end of file diff --git a/platform/ios/core-files.json b/platform/ios/core-files.json index 7c916b027b..08cf1b5946 100644 --- a/platform/ios/core-files.json +++ b/platform/ios/core-files.json @@ -17,6 +17,7 @@ "platform/default/src/mbgl/map/map_snapshotter.cpp", "platform/default/src/mbgl/text/bidi.cpp", "platform/default/src/mbgl/util/compression.cpp", + "platform/default/src/mbgl/util/monotonic_timer.cpp", "platform/default/src/mbgl/util/png_writer.cpp", "platform/default/src/mbgl/util/thread_local.cpp", "platform/default/src/mbgl/util/utf.cpp" diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 26de2430ce..39ae7c6d52 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -52,6 +52,7 @@ macro(mbgl_platform_core) PRIVATE platform/default/src/mbgl/layermanager/layer_manager.cpp PRIVATE platform/default/src/mbgl/util/compression.cpp PRIVATE platform/default/src/mbgl/util/logging_stderr.cpp + PRIVATE platform/default/src/mbgl/util/monotonic_timer.cpp PRIVATE platform/default/src/mbgl/util/string_stdlib.cpp PRIVATE platform/default/src/mbgl/util/thread.cpp PRIVATE platform/default/src/mbgl/util/thread_local.cpp diff --git a/platform/macos/core-files.json b/platform/macos/core-files.json index b0536c4863..5fde52876a 100644 --- a/platform/macos/core-files.json +++ b/platform/macos/core-files.json @@ -16,6 +16,7 @@ "platform/default/src/mbgl/map/map_snapshotter.cpp", "platform/default/src/mbgl/text/bidi.cpp", "platform/default/src/mbgl/util/compression.cpp", + "platform/default/src/mbgl/util/monotonic_timer.cpp", "platform/default/src/mbgl/util/png_writer.cpp", "platform/default/src/mbgl/util/thread_local.cpp", "platform/default/src/mbgl/util/utf.cpp" diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index 1d5a346f22..996a2bc429 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -68,6 +68,12 @@ struct MemoryProbe { } }; +struct FpsProbe { + float average = 0.0; + float minOnePc = 0.0; + float tolerance = 0.0f; +}; + struct NetworkProbe { NetworkProbe() = default; NetworkProbe(size_t requests_, size_t transferred_) : requests(requests_), transferred(transferred_) {} @@ -78,10 +84,11 @@ struct NetworkProbe { class TestMetrics { public: - bool isEmpty() const { return fileSize.empty() && memory.empty() && network.empty(); } + bool isEmpty() const { return fileSize.empty() && memory.empty() && network.empty() && fps.empty(); } std::map fileSize; std::map memory; std::map network; + std::map fps; }; struct TestMetadata { @@ -90,6 +97,7 @@ struct TestMetadata { TestPaths paths; mbgl::JSDocument document; bool renderTest = true; + bool outputsImage = true; mbgl::Size size{ 512u, 512u }; float pixelRatio = 1.0f; diff --git a/render-test/parser.cpp b/render-test/parser.cpp index da5e6bea81..69d6981c02 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -303,6 +303,22 @@ std::string serializeMetrics(const TestMetrics& metrics) { writer.EndArray(); } + if (!metrics.fps.empty()) { + // Start fps section + writer.Key("fps"); + writer.StartArray(); + for (const auto& fpsProbe : metrics.fps) { + assert(!fpsProbe.first.empty()); + writer.StartArray(); + writer.String(fpsProbe.first.c_str()); + writer.Double(fpsProbe.second.average); + writer.Double(fpsProbe.second.minOnePc); + writer.EndArray(); + } + writer.EndArray(); + // End fps section + } + writer.EndObject(); return s.GetString(); @@ -433,6 +449,7 @@ ArgumentsTuple parseArguments(int argc, char** argv) { if (testFilterValue && !std::regex_match(testPath.path().string(), args::get(testFilterValue))) { continue; } + if (testPath.path().filename() == "style.json") { testPaths.emplace_back(testPath, getTestExpectations(testPath, path, expectationsPaths)); } @@ -549,6 +566,23 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { } } + if (document.HasMember("fps")) { + const mbgl::JSValue& fpsValue = document["fps"]; + assert(fpsValue.IsArray()); + for (auto& probeValue : fpsValue.GetArray()) { + assert(probeValue.IsArray()); + assert(probeValue.Size() >= 4u); + assert(probeValue[0].IsString()); + assert(probeValue[1].IsNumber()); // Average + assert(probeValue[2].IsNumber()); // Minimum + assert(probeValue[3].IsNumber()); // Tolerance + const std::string mark{probeValue[0].GetString(), probeValue[0].GetStringLength()}; + assert(!mark.empty()); + result.fps.insert( + {std::move(mark), {probeValue[1].GetFloat(), probeValue[2].GetFloat(), probeValue[3].GetFloat()}}); + } + } + return result; } @@ -607,8 +641,21 @@ TestMetadata parseTestMetadata(const TestPaths& paths) { } if (testValue.HasMember("mapMode")) { + metadata.outputsImage = true; assert(testValue["mapMode"].IsString()); - metadata.mapMode = testValue["mapMode"].GetString() == std::string("tile") ? mbgl::MapMode::Tile : mbgl::MapMode::Static; + std::string mapModeStr = testValue["mapMode"].GetString(); + if (mapModeStr == "tile") + metadata.mapMode = mbgl::MapMode::Tile; + else if (mapModeStr == "continuous") { + metadata.mapMode = mbgl::MapMode::Continuous; + metadata.outputsImage = false; + } else if (mapModeStr == "static") + metadata.mapMode = mbgl::MapMode::Static; + else { + mbgl::Log::Warning( + mbgl::Event::ParseStyle, "Unknown map mode: %s. Falling back to static mode", mapModeStr.c_str()); + metadata.mapMode = mbgl::MapMode::Static; + } } // Test operations handled in runner.cpp. @@ -703,19 +750,21 @@ std::string createResultItem(const TestMetadata& metadata, bool hasFailedTests) html.append("

\n"); html.append(R"(

" + metadata.status + " " + metadata.id + "

\n"); if (metadata.status != "errored") { - if (metadata.renderTest) { - html.append("\n"); - - html.append("\n"); - } else { - html.append("\n"); + if (metadata.outputsImage) { + if (metadata.renderTest) { + html.append("\n"); + + html.append("\n"); + } else { + html.append("\n"); + } } } else { assert(!metadata.errorMessage.empty()); diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index c3a9c6dd77..df1658265a 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -100,7 +100,8 @@ int runRenderTests(int argc, char** argv) { errored = !runner.run(metadata) || !metadata.errorMessage.empty(); } - bool passed = !errored && !metadata.diff.empty() && metadata.difference <= metadata.allowed; + bool passed = + !errored && (!metadata.outputsImage || !metadata.diff.empty()) && metadata.difference <= metadata.allowed; if (shouldIgnore) { if (passed) { diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 1204c72d71..46b890b76c 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -33,12 +34,41 @@ using namespace mbgl; -// static +class TestRunnerMapObserver : public MapObserver { +public: + TestRunnerMapObserver() : mapLoadFailure(false), finishRenderingMap(false), idle(false) {} + + void onDidFailLoadingMap(MapLoadError, const std::string&) override { mapLoadFailure = true; } + + void onDidFinishRenderingMap(RenderMode mode) override final { + if (!finishRenderingMap) finishRenderingMap = mode == RenderMode::Full; + } + + void onDidBecomeIdle() override final { idle = true; } + + void reset() { + mapLoadFailure = false; + finishRenderingMap = false; + idle = false; + } + + bool mapLoadFailure; + bool finishRenderingMap; + bool idle; +}; + +// static const std::string& TestRunner::getBasePath() { const static std::string result = std::string(TEST_RUNNER_ROOT_PATH).append("/mapbox-gl-js/test/integration"); return result; } +// static +gfx::HeadlessBackend::SwapBehaviour swapBehavior(MapMode mode) { + return mode == MapMode::Continuous ? gfx::HeadlessBackend::SwapBehaviour::Flush + : gfx::HeadlessBackend::SwapBehaviour::NoFlush; +} + std::string simpleDiff(const Value& result, const Value& expected) { std::vector resultTokens{tokenize(toJSON(result, 2, false))}; std::vector expectedTokens{tokenize(toJSON(expected, 2, false))}; @@ -159,81 +189,97 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, const std::string& base = metadata.paths.defaultExpectations(); const std::vector& expectations = metadata.paths.expectations; - metadata.actual = mbgl::encodePNG(actualImage); + if (metadata.outputsImage) { + metadata.actual = mbgl::encodePNG(actualImage); - if (actualImage.size.isEmpty()) { - metadata.errorMessage = "Invalid size for actual image"; - return false; - } + if (actualImage.size.isEmpty()) { + metadata.errorMessage = "Invalid size for actual image"; + return false; + } #if !TEST_READ_ONLY - if (getenv("UPDATE_PLATFORM")) { - mbgl::filesystem::create_directories(expectations.back()); - mbgl::util::write_file(expectations.back().string() + "/expected.png", mbgl::encodePNG(actualImage)); - return true; - } else if (getenv("UPDATE_DEFAULT")) { - mbgl::util::write_file(base + "/expected.png", mbgl::encodePNG(actualImage)); - return true; - } else if (getenv("UPDATE_METRICS")) { - if (!metadata.metrics.isEmpty()) { + if (getenv("UPDATE_PLATFORM")) { mbgl::filesystem::create_directories(expectations.back()); - mbgl::util::write_file(expectations.back().string() + "/metrics.json", serializeMetrics(metadata.metrics)); + mbgl::util::write_file(expectations.back().string() + "/expected.png", mbgl::encodePNG(actualImage)); + return true; + } else if (getenv("UPDATE_DEFAULT")) { + mbgl::util::write_file(base + "/expected.png", mbgl::encodePNG(actualImage)); return true; } - } - mbgl::util::write_file(base + "/actual.png", metadata.actual); + mbgl::util::write_file(base + "/actual.png", metadata.actual); #endif - mbgl::PremultipliedImage expectedImage { actualImage.size }; - mbgl::PremultipliedImage imageDiff { actualImage.size }; + mbgl::PremultipliedImage expectedImage{actualImage.size}; + mbgl::PremultipliedImage imageDiff{actualImage.size}; - double pixels = 0.0; - std::vector expectedImagesPaths; - mbgl::filesystem::path expectedMetricsPath; - for (auto rit = expectations.rbegin(); rit!= expectations.rend(); ++rit) { - if (mbgl::filesystem::exists(*rit)) { - if (metadata.expectedMetrics.isEmpty()) { - mbgl::filesystem::path maybeExpectedMetricsPath{ *rit }; - maybeExpectedMetricsPath.replace_filename("metrics.json"); - metadata.expectedMetrics = readExpectedMetrics(maybeExpectedMetricsPath); + double pixels = 0.0; + std::vector expectedImagesPaths; + for (auto rit = expectations.rbegin(); rit != expectations.rend(); ++rit) { + if (mbgl::filesystem::exists(*rit)) { + expectedImagesPaths = readExpectedImageEntries(*rit); + if (!expectedImagesPaths.empty()) break; } - expectedImagesPaths = readExpectedImageEntries(*rit); - if (!expectedImagesPaths.empty()) break; } - } - if (expectedImagesPaths.empty()) { - metadata.errorMessage = "Failed to find expectations for: " + metadata.paths.stylePath.string(); - return false; - } - - for (const auto& entry: expectedImagesPaths) { - mbgl::optional maybeExpectedImage = mbgl::util::readFile(entry); - if (!maybeExpectedImage) { - metadata.errorMessage = "Failed to load expected image " + entry; + if (expectedImagesPaths.empty()) { + metadata.errorMessage = "Failed to find expectations for: " + metadata.paths.stylePath.string(); return false; } - metadata.expected = *maybeExpectedImage; + for (const auto& entry : expectedImagesPaths) { + mbgl::optional maybeExpectedImage = mbgl::util::readFile(entry); + if (!maybeExpectedImage) { + metadata.errorMessage = "Failed to load expected image " + entry; + return false; + } + + metadata.expected = *maybeExpectedImage; - expectedImage = mbgl::decodeImage(*maybeExpectedImage); + expectedImage = mbgl::decodeImage(*maybeExpectedImage); - pixels = // implicitly converting from uint64_t - mapbox::pixelmatch(actualImage.data.get(), expectedImage.data.get(), expectedImage.size.width, - expectedImage.size.height, imageDiff.data.get(), 0.1285); // Defined in GL JS + pixels = // implicitly converting from uint64_t + mapbox::pixelmatch(actualImage.data.get(), + expectedImage.data.get(), + expectedImage.size.width, + expectedImage.size.height, + imageDiff.data.get(), + 0.1285); // Defined in GL JS - metadata.diff = mbgl::encodePNG(imageDiff); + metadata.diff = mbgl::encodePNG(imageDiff); #if !TEST_READ_ONLY - mbgl::util::write_file(base + "/diff.png", metadata.diff); + mbgl::util::write_file(base + "/diff.png", metadata.diff); #endif - metadata.difference = pixels / expectedImage.size.area(); - if (metadata.difference <= metadata.allowed) { - break; + metadata.difference = pixels / expectedImage.size.area(); + if (metadata.difference <= metadata.allowed) { + break; + } + } + } + +#if !TEST_READ_ONLY + if (getenv("UPDATE_METRICS")) { + if (!metadata.metrics.isEmpty()) { + mbgl::filesystem::create_directories(expectations.back()); + mbgl::util::write_file(expectations.back().string() + "/metrics.json", serializeMetrics(metadata.metrics)); + return true; + } + } +#endif + + mbgl::filesystem::path expectedMetricsPath; + for (auto rit = expectations.rbegin(); rit != expectations.rend(); ++rit) { + if (mbgl::filesystem::exists(*rit)) { + if (metadata.expectedMetrics.isEmpty()) { + mbgl::filesystem::path maybeExpectedMetricsPath{*rit}; + maybeExpectedMetricsPath.replace_filename("metrics.json"); + metadata.expectedMetrics = readExpectedMetrics(maybeExpectedMetricsPath); + } } } + // Check file size metrics. for (const auto& expected : metadata.expectedMetrics.fileSize) { auto actual = metadata.metrics.fileSize.find(expected.first); @@ -317,16 +363,38 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, } } #endif // !defined(SANITIZE) + // Check fps metrics + for (const auto& expected : metadata.expectedMetrics.fps) { + auto actual = metadata.metrics.fps.find(expected.first); + if (actual == metadata.metrics.fps.end()) { + metadata.errorMessage = "Failed to find fps probe: " + expected.first; + return false; + } + auto result = checkValue(expected.second.average, actual->second.average, expected.second.tolerance); + if (!std::get(result)) { + std::stringstream ss; + ss << "Average fps at probe \"" << expected.first << "\" is " << actual->second.average + << ", expected to be " << expected.second.average << " with tolerance of " << expected.second.tolerance; + metadata.errorMessage = ss.str(); + return false; + } + result = checkValue(expected.second.minOnePc, actual->second.minOnePc, expected.second.tolerance); + if (!std::get(result)) { + std::stringstream ss; + ss << "Minimum(1%) fps at probe \"" << expected.first << "\" is " << actual->second.minOnePc + << ", expected to be " << expected.second.minOnePc << " with tolerance of " << expected.second.tolerance; + metadata.errorMessage = ss.str(); + return false; + } + } return true; } bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { - if (!metadata.document.HasMember("metadata") || - !metadata.document["metadata"].HasMember("test") || + if (!metadata.document.HasMember("metadata") || !metadata.document["metadata"].HasMember("test") || !metadata.document["metadata"]["test"].HasMember("operations")) { return true; } - assert(metadata.document["metadata"]["test"]["operations"].IsArray()); const auto& operationsArray = metadata.document["metadata"]["test"]["operations"].GetArray(); @@ -342,6 +410,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { auto& frontend = maps[key]->frontend; auto& map = maps[key]->map; + auto& observer = maps[key]->observer; static const std::string waitOp("wait"); static const std::string sleepOp("sleep"); @@ -372,6 +441,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { static const std::string setFeatureStateOp("setFeatureState"); static const std::string getFeatureStateOp("getFeatureState"); static const std::string removeFeatureStateOp("removeFeatureState"); + static const std::string panGestureOp("panGesture"); if (operationArray[0].GetString() == waitOp) { // wait @@ -813,9 +883,76 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { return false; } frontend.getRenderer()->removeFeatureState(sourceID, sourceLayer, featureID, stateKey); + } else if (operationArray[0].GetString() == panGestureOp) { + // benchmarkPanGesture + assert(operationArray.Size() >= 4u); + assert(operationArray[1].IsString()); // identifier + assert(operationArray[2].IsNumber()); // duration + assert(operationArray[3].IsArray()); // start [lat, lng, zoom] + assert(operationArray[4].IsArray()); // end [lat, lng, zoom] + + if (metadata.mapMode != mbgl::MapMode::Continuous) { + metadata.errorMessage = "Map mode must be Continous for " + panGestureOp + " operation"; + return false; + } + + std::string mark = operationArray[1].GetString(); + int duration = operationArray[2].GetFloat(); + LatLng startPos, endPos; + double startZoom, endZoom; + std::vector samples; + + auto parsePosition = [](auto arr) -> std::tuple { + assert(arr.Size() >= 3); + return {{arr[1].GetDouble(), arr[0].GetDouble()}, arr[2].GetDouble()}; + }; + + std::tie(startPos, startZoom) = parsePosition(operationArray[3].GetArray()); + std::tie(endPos, endZoom) = parsePosition(operationArray[4].GetArray()); + + // Jump to the starting point of the segment and make sure there's something to render + map.jumpTo(mbgl::CameraOptions().withCenter(startPos).withZoom(startZoom)); + + observer->reset(); + while (!observer->finishRenderingMap) { + frontend.renderOnce(map); + } + + if (observer->mapLoadFailure) return false; + + size_t frames = 0; + float totalTime = 0.0; + bool transitionFinished = false; + + mbgl::AnimationOptions animationOptions(mbgl::Milliseconds(duration * 1000)); + animationOptions.minZoom = util::min(startZoom, endZoom); + animationOptions.transitionFinishFn = [&]() { transitionFinished = true; }; + + map.flyTo(mbgl::CameraOptions().withCenter(endPos).withZoom(endZoom), animationOptions); + + for (; !transitionFinished; frames++) { + frontend.renderOnce(map); + float frameTime = (float)frontend.getFrameTime(); + totalTime += frameTime; + + samples.push_back(frameTime); + } + + float averageFps = totalTime > 0.0 ? frames / totalTime : 0.0; + float minFrameTime = 0.0; + + // Use 1% of the longest frames to compute the minimum fps + std::sort(samples.begin(), samples.end()); + + int sampleCount = util::max(1, (int)samples.size() / 100); + for (auto it = samples.rbegin(); it != samples.rbegin() + sampleCount; it++) minFrameTime += *it; + + float minOnePcFps = sampleCount / minFrameTime; + + metadata.metrics.fps.insert({std::move(mark), {averageFps, minOnePcFps, 0.0f}}); } else { - metadata.errorMessage = std::string("Unsupported operation: ") + operationArray[0].GetString(); + metadata.errorMessage = std::string("Unsupported operation: ") + operationArray[0].GetString(); return false; } @@ -824,9 +961,10 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { } TestRunner::Impl::Impl(const TestMetadata& metadata) - : frontend(metadata.size, metadata.pixelRatio), + : observer(std::make_unique()), + frontend(metadata.size, metadata.pixelRatio, swapBehavior(metadata.mapMode)), map(frontend, - mbgl::MapObserver::nullObserver(), + *observer.get(), mbgl::MapOptions() .withMapMode(metadata.mapMode) .withSize(metadata.size) @@ -834,6 +972,8 @@ TestRunner::Impl::Impl(const TestMetadata& metadata) .withCrossSourceCollisions(metadata.crossSourceCollisions), mbgl::ResourceOptions().withCacheOnlyRequestsSupport(false)) {} +TestRunner::Impl::~Impl() {} + bool TestRunner::run(TestMetadata& metadata) { AllocationIndex::setActive(false); AllocationIndex::reset(); @@ -864,7 +1004,7 @@ bool TestRunner::run(TestMetadata& metadata) { mbgl::PremultipliedImage image; try { - image = frontend.render(map); + if (metadata.outputsImage) image = frontend.render(map); } catch (const std::exception&) { return false; } diff --git a/render-test/runner.hpp b/render-test/runner.hpp index ea593bcc61..6aba2d2391 100644 --- a/render-test/runner.hpp +++ b/render-test/runner.hpp @@ -5,6 +5,7 @@ #include +class TestRunnerMapObserver; struct TestMetadata; class TestRunner { @@ -26,7 +27,9 @@ private: struct Impl { Impl(const TestMetadata&); + ~Impl(); + std::unique_ptr observer; mbgl::HeadlessFrontend frontend; mbgl::Map map; }; diff --git a/src/core-files.json b/src/core-files.json index e5fa493312..e8795fbdd3 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -483,6 +483,7 @@ "mbgl/util/indexed_tuple.hpp": "include/mbgl/util/indexed_tuple.hpp", "mbgl/util/interpolate.hpp": "include/mbgl/util/interpolate.hpp", "mbgl/util/logging.hpp": "include/mbgl/util/logging.hpp", + "mbgl/util/monotonic_timer.hpp": "include/mbgl/util/monotonic_timer.hpp", "mbgl/util/noncopyable.hpp": "include/mbgl/util/noncopyable.hpp", "mbgl/util/optional.hpp": "include/mbgl/util/optional.hpp", "mbgl/util/platform.hpp": "include/mbgl/util/platform.hpp", diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 18b376e3dc..f81ac48ee5 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -583,6 +583,10 @@ std::unique_ptr Context::createCommandEncoder() { return std::make_unique(*this); } +void Context::finish() { + MBGL_CHECK_ERROR(glFinish()); +} + void Context::draw(const gfx::DrawMode& drawMode, std::size_t indexOffset, std::size_t indexLength) { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 70f12e5a8d..edcdde1ec6 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -92,6 +92,8 @@ public: std::size_t indexOffset, std::size_t indexLength); + void finish(); + // Actually remove the objects we marked as abandoned with the above methods. // Only call this while the OpenGL context is exclusive to this thread. void performCleanup() override; diff --git a/test/gl/context.test.cpp b/test/gl/context.test.cpp index 770434c5be..5c42eb9344 100644 --- a/test/gl/context.test.cpp +++ b/test/gl/context.test.cpp @@ -91,9 +91,10 @@ TEST(GLContextMode, Shared) { util::RunLoop loop; - HeadlessFrontend frontend { 1, gfx::ContextMode::Shared }; + HeadlessFrontend frontend{1, gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode::Shared}; - Map map(frontend, MapObserver::nullObserver(), + Map map(frontend, + MapObserver::nullObserver(), MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()), ResourceOptions().withCachePath(":memory:").withAssetPath("test/fixtures/api/assets")); map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json")); diff --git a/test/text/local_glyph_rasterizer.test.cpp b/test/text/local_glyph_rasterizer.test.cpp index 2722ee5849..94c37b170b 100644 --- a/test/text/local_glyph_rasterizer.test.cpp +++ b/test/text/local_glyph_rasterizer.test.cpp @@ -33,9 +33,7 @@ namespace { class LocalGlyphRasterizerTest { public: LocalGlyphRasterizerTest(const optional fontFamily) - : frontend(1, gfx::ContextMode::Unique, fontFamily) - { - } + : frontend(1, gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode::Unique, fontFamily) {} util::RunLoop loop; std::shared_ptr fileSource = std::make_shared(); -- cgit v1.2.1 From ab603c5fed833d574c51e2296d7d37014aeaa81b Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 21 Oct 2019 18:15:50 +0300 Subject: [core] Enable incremental vacuum for Offline DB Thus we avoid re-creating the whole database and keeping the backup file as it happens on calling VACUUM. --- .../include/mbgl/storage/offline_database.hpp | 1 + .../default/src/mbgl/storage/offline_database.cpp | 20 ++++++-- test/fixtures/offline_database/no_auto_vacuum.db | Bin 0 -> 61440 bytes test/storage/offline_database.test.cpp | 52 ++++++++++++++++++--- 4 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 test/fixtures/offline_database/no_auto_vacuum.db diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp index 96b867eaa6..e599094a6d 100644 --- a/platform/default/include/mbgl/storage/offline_database.hpp +++ b/platform/default/include/mbgl/storage/offline_database.hpp @@ -108,6 +108,7 @@ private: void migrateToVersion6(); void cleanup(); bool disabled(); + void vacuum(); mapbox::sqlite::Statement& getStatement(const char *); diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp index 133e1f7992..5aa5738f41 100644 --- a/platform/default/src/mbgl/storage/offline_database.cpp +++ b/platform/default/src/mbgl/storage/offline_database.cpp @@ -140,11 +140,12 @@ void OfflineDatabase::removeExisting() { void OfflineDatabase::removeOldCacheTable() { assert(db); db->exec("DROP TABLE IF EXISTS http_cache"); - db->exec("VACUUM"); + vacuum(); } void OfflineDatabase::createSchema() { assert(db); + vacuum(); db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); mapbox::sqlite::Transaction transaction(*db); @@ -155,7 +156,7 @@ void OfflineDatabase::createSchema() { void OfflineDatabase::migrateToVersion3() { assert(db); - db->exec("VACUUM"); + vacuum(); db->exec("PRAGMA user_version = 3"); } @@ -181,6 +182,15 @@ void OfflineDatabase::migrateToVersion6() { transaction.commit(); } +void OfflineDatabase::vacuum() { + if (getPragma("PRAGMA auto_vacuum") != 2 /*INCREMENTAL*/) { + db->exec("PRAGMA auto_vacuum = INCREMENTAL"); + db->exec("VACUUM"); + } else { + db->exec("PRAGMA incremental_vacuum"); + } +} + mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) { if (!db) { initialize(); @@ -683,7 +693,7 @@ std::exception_ptr OfflineDatabase::clearAmbientCache() try { resourceQuery.run(); - db->exec("VACUUM"); + vacuum(); return nullptr; } catch (const mapbox::sqlite::Exception& ex) { @@ -871,7 +881,7 @@ std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try { evict(0); assert(db); - db->exec("VACUUM"); + vacuum(); // Ensure that the cached offlineTileCount value is recalculated. offlineMapboxTileCount = {}; @@ -1218,7 +1228,7 @@ std::exception_ptr OfflineDatabase::setMaximumAmbientCacheSize(uint64_t size) { if (databaseSize > maximumAmbientCacheSize) { evict(0); - db->exec("VACUUM"); + vacuum(); } return nullptr; diff --git a/test/fixtures/offline_database/no_auto_vacuum.db b/test/fixtures/offline_database/no_auto_vacuum.db new file mode 100644 index 0000000000..f19e639933 Binary files /dev/null and b/test/fixtures/offline_database/no_auto_vacuum.db differ diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 24234b0624..7b5255c9f5 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -92,6 +92,14 @@ static std::vector databaseTableColumns(const std::string& path, co return columns; } +static int databaseAutoVacuum(const std::string& path) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{db, "pragma auto_vacuum"}; + mapbox::sqlite::Query query{stmt}; + query.run(); + return query.get(0); +} + namespace fixture { const Resource resource{ Resource::Style, "mapbox://test" }; @@ -1360,13 +1368,45 @@ TEST(OfflineDatabase, MigrateFromV5Schema) { EXPECT_EQ(6, databaseUserVersion(filename)); - EXPECT_EQ((std::vector{ "id", "url_template", "pixel_ratio", "z", "x", "y", - "expires", "modified", "etag", "data", "compressed", - "accessed", "must_revalidate" }), + EXPECT_EQ((std::vector{"id", + "url_template", + "pixel_ratio", + "z", + "x", + "y", + "expires", + "modified", + "etag", + "data", + "compressed", + "accessed", + "must_revalidate"}), databaseTableColumns(filename, "tiles")); - EXPECT_EQ((std::vector{ "id", "url", "kind", "expires", "modified", "etag", "data", - "compressed", "accessed", "must_revalidate" }), - databaseTableColumns(filename, "resources")); + EXPECT_EQ( + (std::vector{ + "id", "url", "kind", "expires", "modified", "etag", "data", "compressed", "accessed", "must_revalidate"}), + databaseTableColumns(filename, "resources")); + + EXPECT_EQ(0u, log.uncheckedCount()); +} + +TEST(OfflineDatabase, IncrementalVacuum) { + FixtureLog log; + deleteDatabaseFiles(); + util::copyFile(filename, "test/fixtures/offline_database/no_auto_vacuum.db"); + EXPECT_EQ(0, databaseAutoVacuum(filename)); + + { + OfflineDatabase db(filename); + db.setMaximumAmbientCacheSize(0); + + auto regions = db.listRegions().value(); + for (auto& region : regions) { + db.deleteRegion(std::move(region)); + } + } + + EXPECT_EQ(2, databaseAutoVacuum(filename)); EXPECT_EQ(0u, log.uncheckedCount()); } -- cgit v1.2.1 From 2cdc09dbb13964ffd2af1e8776a56c70f80e0360 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 22 Oct 2019 14:35:43 +0300 Subject: [ios][android] Add change log entries --- platform/android/CHANGELOG.md | 5 +++++ platform/ios/CHANGELOG.md | 1 + 2 files changed, 6 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 8fb977140c..cc572194e8 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,11 @@ 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. +## master + +### Performance improvements + - Enable incremental vacuum for the offline database in order to make data removal requests faster and to avoid the excessive disk space usage (creating a backup file on VACUUM call) [#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837) + ## 8.5.0-alpha.2 - October 10, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.5.0-alpha.1...android-v8.5.0-alpha.2) since [Mapbox Maps SDK for Android v8.5.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.5.0-alpha.1): diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 03ed8cdc46..0c776b0944 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 ### Other changes * Coalesce requests to the client for the same missing image ([#15778](https://github.com/mapbox/mapbox-gl-native/pull/15778)) +* Enable incremental vacuum for the offline database in order to make data removal requests faster and to avoid the excessive disk space usage (creating a backup file on VACUUM call). ([#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837)) ## 5.5.0 -- cgit v1.2.1 From 068befa9df1c55904ec7e26bee062e5e33aecbce Mon Sep 17 00:00:00 2001 From: zmiao Date: Tue, 22 Oct 2019 16:32:21 +0300 Subject: [test-runner] Run render test runner as a NativeActivity app on android device (#15827) * [test-runner]Add android render-test-runner NativeActivity app * [test-runner] Fix cmake for CI build failure * [test-runner] Update folder location, change app configureation * [test-runner] Add running instruction --- benchmark/fixtures/api/cache.db | Bin 1298432 -> 1298432 bytes next/benchmark/CMakeLists.txt | 6 +- next/platform/android/android.cmake | 68 +++++++-- next/render-test/CMakeLists.txt | 6 +- next/test/CMakeLists.txt | 1 + platform/android/src/test/render_test_collator.cpp | 40 +++++ .../android/src/test/render_test_number_format.cpp | 15 ++ platform/android/src/test/render_test_runner.cpp | 57 +++++++ render-test/android/README.md | 9 ++ render-test/android/app/build.gradle | 29 ++++ .../android/app/src/main/AndroidManifest.xml | 26 ++++ .../app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes .../app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes .../app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../app/src/main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes .../android/app/src/main/res/values/strings.xml | 4 + render-test/android/build.gradle | 16 ++ render-test/android/gradle.properties | 1 + .../android/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + render-test/android/gradlew | 164 +++++++++++++++++++++ render-test/android/gradlew.bat | 90 +++++++++++ render-test/android/render_test_setup.sh | 38 +++++ render-test/android/settings.gradle | 2 + render-test/include/mbgl/render_test.hpp | 5 +- render-test/parser.cpp | 3 +- 26 files changed, 565 insertions(+), 21 deletions(-) create mode 100644 platform/android/src/test/render_test_collator.cpp create mode 100644 platform/android/src/test/render_test_number_format.cpp create mode 100644 platform/android/src/test/render_test_runner.cpp create mode 100644 render-test/android/README.md create mode 100644 render-test/android/app/build.gradle create mode 100644 render-test/android/app/src/main/AndroidManifest.xml create mode 100644 render-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 render-test/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 render-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 render-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 render-test/android/app/src/main/res/values/strings.xml create mode 100644 render-test/android/build.gradle create mode 100644 render-test/android/gradle.properties create mode 100644 render-test/android/gradle/wrapper/gradle-wrapper.jar create mode 100644 render-test/android/gradle/wrapper/gradle-wrapper.properties create mode 100755 render-test/android/gradlew create mode 100644 render-test/android/gradlew.bat create mode 100755 render-test/android/render_test_setup.sh create mode 100644 render-test/android/settings.gradle diff --git a/benchmark/fixtures/api/cache.db b/benchmark/fixtures/api/cache.db index fc51eca3b9..64cd376892 100644 Binary files a/benchmark/fixtures/api/cache.db and b/benchmark/fixtures/api/cache.db differ diff --git a/next/benchmark/CMakeLists.txt b/next/benchmark/CMakeLists.txt index 2ae1227d91..117d556041 100644 --- a/next/benchmark/CMakeLists.txt +++ b/next/benchmark/CMakeLists.txt @@ -31,7 +31,11 @@ get_target_property(MBGL_CORE_PRIVATE_LIBRARIES mbgl-core LINK_LIBRARIES) target_link_libraries( mbgl-benchmark - PRIVATE ${MBGL_CORE_PRIVATE_LIBRARIES} mbgl-core mbgl-vendor-benchmark + PRIVATE + ${MBGL_CORE_PRIVATE_LIBRARIES} + mbgl-vendor-benchmark + mbgl-core + $<$:mbgl-core-android> ) if(CMAKE_SYSTEM_NAME STREQUAL Android) diff --git a/next/platform/android/android.cmake b/next/platform/android/android.cmake index 6032294ff7..06183291db 100644 --- a/next/platform/android/android.cmake +++ b/next/platform/android/android.cmake @@ -40,8 +40,6 @@ target_sources( ${MBGL_ROOT}/platform/android/src/conversion/constant.cpp ${MBGL_ROOT}/platform/android/src/conversion/constant.hpp ${MBGL_ROOT}/platform/android/src/conversion/conversion.hpp - ${MBGL_ROOT}/platform/android/src/file_source.cpp - ${MBGL_ROOT}/platform/android/src/file_source.hpp ${MBGL_ROOT}/platform/android/src/geojson/feature.cpp ${MBGL_ROOT}/platform/android/src/geojson/feature.hpp ${MBGL_ROOT}/platform/android/src/geojson/feature_collection.cpp @@ -85,10 +83,6 @@ target_sources( ${MBGL_ROOT}/platform/android/src/gson/json_primitive.cpp ${MBGL_ROOT}/platform/android/src/gson/json_primitive.hpp ${MBGL_ROOT}/platform/android/src/http_file_source.cpp - ${MBGL_ROOT}/platform/android/src/i18n/collator.cpp - ${MBGL_ROOT}/platform/android/src/i18n/collator_jni.hpp - ${MBGL_ROOT}/platform/android/src/i18n/number_format.cpp - ${MBGL_ROOT}/platform/android/src/i18n/number_format_jni.hpp ${MBGL_ROOT}/platform/android/src/image.cpp ${MBGL_ROOT}/platform/android/src/java/util.cpp ${MBGL_ROOT}/platform/android/src/java/util.hpp @@ -98,9 +92,6 @@ target_sources( ${MBGL_ROOT}/platform/android/src/jni.hpp ${MBGL_ROOT}/platform/android/src/jni_native.cpp ${MBGL_ROOT}/platform/android/src/jni_native.hpp - ${MBGL_ROOT}/platform/android/src/logger.cpp - ${MBGL_ROOT}/platform/android/src/logger.hpp - ${MBGL_ROOT}/platform/android/src/logging_android.cpp ${MBGL_ROOT}/platform/android/src/mapbox.cpp ${MBGL_ROOT}/platform/android/src/mapbox.hpp ${MBGL_ROOT}/platform/android/src/map/camera_position.cpp @@ -193,8 +184,6 @@ target_sources( ${MBGL_ROOT}/platform/android/src/style/transition_options.hpp ${MBGL_ROOT}/platform/android/src/style/value.cpp ${MBGL_ROOT}/platform/android/src/style/value.hpp - ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer.cpp - ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer_jni.hpp ${MBGL_ROOT}/platform/android/src/thread.cpp ${MBGL_ROOT}/platform/android/src/timer.cpp ${MBGL_ROOT}/platform/default/src/mbgl/gfx/headless_backend.cpp @@ -243,14 +232,44 @@ target_link_libraries( z ) +add_library( + mbgl-core-android STATIC + ${MBGL_ROOT}/platform/android/src/file_source.cpp + ${MBGL_ROOT}/platform/android/src/file_source.hpp + ${MBGL_ROOT}/platform/android/src/i18n/collator.cpp + ${MBGL_ROOT}/platform/android/src/i18n/collator_jni.hpp + ${MBGL_ROOT}/platform/android/src/i18n/number_format.cpp + ${MBGL_ROOT}/platform/android/src/i18n/number_format_jni.hpp + ${MBGL_ROOT}/platform/android/src/logger.cpp + ${MBGL_ROOT}/platform/android/src/logger.hpp + ${MBGL_ROOT}/platform/android/src/logging_android.cpp + ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer.cpp + ${MBGL_ROOT}/platform/android/src/text/local_glyph_rasterizer_jni.hpp +) + +target_include_directories( + mbgl-core-android + PRIVATE ${MBGL_ROOT}/platform/default/include ${MBGL_ROOT}/src +) + +target_link_libraries( + mbgl-core-android + PRIVATE Mapbox::Base::jni.hpp mbgl-core +) + add_library( mapbox-gl SHARED ${MBGL_ROOT}/platform/android/src/main.cpp ) +target_include_directories( + mapbox-gl + PRIVATE ${MBGL_ROOT}/platform/default/include ${MBGL_ROOT}/src +) + target_link_libraries( mapbox-gl - PRIVATE Mapbox::Base::jni.hpp mbgl-core + PRIVATE Mapbox::Base::jni.hpp mbgl-core mbgl-core-android ) add_library( @@ -296,15 +315,40 @@ target_link_libraries( PRIVATE Mapbox::Base::jni.hpp mapbox-gl mbgl-benchmark ) +add_library( + mbgl-render-test-runner SHARED + ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c + ${MBGL_ROOT}/platform/android/src/test/render_test_runner.cpp + ${MBGL_ROOT}/platform/default/src/mbgl/text/local_glyph_rasterizer.cpp + ${MBGL_ROOT}/platform/android/src/test/render_test_collator.cpp + ${MBGL_ROOT}/platform/android/src/test/render_test_number_format.cpp +) + +target_include_directories( + mbgl-render-test-runner + PRIVATE ${ANDROID_NDK}/sources/android/native_app_glue ${MBGL_ROOT}/platform/android/src ${MBGL_ROOT}/src +) + +target_link_libraries( + mbgl-render-test-runner + PRIVATE + Mapbox::Base::jni.hpp + android + log + mbgl-render-test +) + # Android has no concept of MinSizeRel on android.toolchain.cmake and provides configurations tuned for binary size. We can push it a bit # more with code folding and LTO. set_target_properties(example-custom-layer PROPERTIES LINK_FLAGS_RELEASE "-fuse-ld=gold -O2 -flto -Wl,--icf=safe") set_target_properties(mapbox-gl PROPERTIES LINK_FLAGS_RELEASE "-fuse-ld=gold -O2 -flto -Wl,--icf=safe") set_target_properties(mbgl-benchmark-runner PROPERTIES LINK_FLAGS_RELEASE "-fuse-ld=gold -O2 -flto -Wl,--icf=safe") +set_target_properties(mbgl-render-test-runner PROPERTIES LINK_FLAGS_RELEASE "-fuse-ld=gold -O2 -flto -Wl,--icf=safe") set_target_properties(mbgl-test-runner PROPERTIES LINK_FLAGS_RELEASE "-fuse-ld=gold -O2 -flto -Wl,--icf=safe") target_compile_options(example-custom-layer PRIVATE $<$:-Qunused-arguments -flto>) target_compile_options(mapbox-gl PRIVATE $<$:-Qunused-arguments -flto>) target_compile_options(mbgl-core PRIVATE $<$:-Qunused-arguments -flto>) +target_compile_options(mbgl-render-test-runner PRIVATE $<$:-Qunused-arguments -flto>) target_compile_options(mbgl-vendor-icu PRIVATE $<$:-Qunused-arguments -flto>) target_compile_options(mbgl-vendor-sqlite PRIVATE $<$:-Qunused-arguments -flto>) diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index b3aa20ba62..02ee6141cf 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -1,5 +1,5 @@ add_library( - mbgl-render-test SHARED EXCLUDE_FROM_ALL + mbgl-render-test STATIC EXCLUDE_FROM_ALL ${MBGL_ROOT}/expression-test/test_runner_common.cpp ${MBGL_ROOT}/expression-test/test_runner_common.hpp ${MBGL_ROOT}/render-test/allocation_index.cpp @@ -24,7 +24,7 @@ target_compile_definitions( # FIXME: Should not use core private interface target_include_directories( mbgl-render-test - PRIVATE ${MBGL_ROOT}/src + PRIVATE ${MBGL_ROOT}/src ${MBGL_ROOT}/platform/default/include ) target_include_directories( @@ -40,8 +40,8 @@ target_link_libraries( Mapbox::Base::Extras::args Mapbox::Base::Extras::filesystem Mapbox::Base::pixelmatch-cpp - mbgl-core mbgl-vendor-boost + PUBLIC mbgl-core ) if(CMAKE_SYSTEM_NAME STREQUAL Android) diff --git a/next/test/CMakeLists.txt b/next/test/CMakeLists.txt index 586e2bbdaa..4995fa4e56 100644 --- a/next/test/CMakeLists.txt +++ b/next/test/CMakeLists.txt @@ -153,6 +153,7 @@ target_link_libraries( Mapbox::Base::Extras::args Mapbox::Base::pixelmatch-cpp mbgl-core + $<$:mbgl-core-android> ) target_link_libraries( diff --git a/platform/android/src/test/render_test_collator.cpp b/platform/android/src/test/render_test_collator.cpp new file mode 100644 index 0000000000..e6e3b27b48 --- /dev/null +++ b/platform/android/src/test/render_test_collator.cpp @@ -0,0 +1,40 @@ +#include + +#include + +namespace mbgl { +namespace platform { + +class Collator::Impl { +public: + Impl(bool caseSensitive_, bool diacriticSensitive_, optional) + : caseSensitive(caseSensitive_), diacriticSensitive(diacriticSensitive_) {} + + bool operator==(const Impl& other) const { return true; } + + int compare(const std::string& lhs, const std::string& rhs) const { return 0; } + + std::string resolvedLocale() const { return ""; } + +private: + bool caseSensitive; + bool diacriticSensitive; +}; + +Collator::Collator(bool caseSensitive, bool diacriticSensitive, optional locale_) + : impl(std::make_shared(caseSensitive, diacriticSensitive, std::move(locale_))) {} + +int Collator::compare(const std::string& lhs, const std::string& rhs) const { + return impl->compare(lhs, rhs); +} + +bool Collator::operator==(const Collator& other) const { + return *impl == *(other.impl); +} + +std::string Collator::resolvedLocale() const { + return impl->resolvedLocale(); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/android/src/test/render_test_number_format.cpp b/platform/android/src/test/render_test_number_format.cpp new file mode 100644 index 0000000000..57710c8558 --- /dev/null +++ b/platform/android/src/test/render_test_number_format.cpp @@ -0,0 +1,15 @@ +#include + +namespace mbgl { +namespace platform { + +std::string formatNumber(double /*number*/, + const std::string& /*localeId */, + const std::string& /*currency*/, + uint8_t /*minFractionDigits*/, + uint8_t /*maxFractionDigits*/) { + return ""; +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/android/src/test/render_test_runner.cpp b/platform/android/src/test/render_test_runner.cpp new file mode 100644 index 0000000000..3f85140128 --- /dev/null +++ b/platform/android/src/test/render_test_runner.cpp @@ -0,0 +1,57 @@ +#include +#include +#include "jni.hpp" +#include "logger.hpp" + +#include +#include + +#include + +#include + +namespace mbgl { + +namespace { + +int severityToPriority(EventSeverity severity) { + switch (severity) { + case EventSeverity::Debug: + return ANDROID_LOG_DEBUG; + + case EventSeverity::Info: + return ANDROID_LOG_INFO; + + case EventSeverity::Warning: + return ANDROID_LOG_WARN; + + case EventSeverity::Error: + return ANDROID_LOG_ERROR; + + default: + return ANDROID_LOG_VERBOSE; + } +} + +} // namespace + +void Log::platformRecord(EventSeverity severity, const std::string& msg) { + __android_log_print(severityToPriority(severity), "mbgl", "%s", msg.c_str()); +} + +} // namespace mbgl + +void android_main(struct android_app* app) { + mbgl::android::theJVM = app->activity->vm; + JNIEnv* env; + app->activity->vm->AttachCurrentThread(&env, NULL); + + std::vector arguments = {"mbgl-render-test-runner", "-p", "/sdcard/render-test"}; + std::vector argv; + for (const auto& arg : arguments) { + argv.push_back((char*)arg.data()); + } + argv.push_back(nullptr); + (void)mbgl::runRenderTests(argv.size() - 1, argv.data()); + app->activity->vm->DetachCurrentThread(); +} \ No newline at end of file diff --git a/render-test/android/README.md b/render-test/android/README.md new file mode 100644 index 0000000000..270c970fce --- /dev/null +++ b/render-test/android/README.md @@ -0,0 +1,9 @@ +# RenderTestRunner + +This app is a purely native application, with no Java source code, that can run **mbgl-render-test-runner** on android devices. + + +## Setup the test environment +- Run render_test_setup.sh so that all the necessary test resources are pushed to the device. + +- Switch on storage permission of the app so that it can read/write data on SD card. \ No newline at end of file diff --git a/render-test/android/app/build.gradle b/render-test/android/app/build.gradle new file mode 100644 index 0000000000..60609e3ba2 --- /dev/null +++ b/render-test/android/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + + defaultConfig { + applicationId = 'com.mapbox.mapboxsdk.maps.render_test_runner' + minSdkVersion 14 + targetSdkVersion 28 + externalNativeBuild { + cmake { + arguments '-DANDROID_CCACHE=ccache' + arguments '-DANDROID_STL=c++_static' + targets 'mbgl-render-test-runner' + } + } + } + externalNativeBuild { + cmake { + version '3.10.2' + path '../../../next/CMakeLists.txt' + } + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' +} diff --git a/render-test/android/app/src/main/AndroidManifest.xml b/render-test/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..6c7af7ed8f --- /dev/null +++ b/render-test/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + diff --git a/render-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/render-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000..cde69bccce Binary files /dev/null and b/render-test/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/render-test/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/render-test/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000..c133a0cbd3 Binary files /dev/null and b/render-test/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/render-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/render-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000..bfa42f0e7b Binary files /dev/null and b/render-test/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/render-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/render-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000..324e72cdd7 Binary files /dev/null and b/render-test/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/render-test/android/app/src/main/res/values/strings.xml b/render-test/android/app/src/main/res/values/strings.xml new file mode 100644 index 0000000000..00b181ca34 --- /dev/null +++ b/render-test/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + RenderTestRunner + diff --git a/render-test/android/build.gradle b/render-test/android/build.gradle new file mode 100644 index 0000000000..e58b831f71 --- /dev/null +++ b/render-test/android/build.gradle @@ -0,0 +1,16 @@ +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.5.1' + } +} + +allprojects { + repositories { + google() + jcenter() + } +} diff --git a/render-test/android/gradle.properties b/render-test/android/gradle.properties new file mode 100644 index 0000000000..2427fd0bf4 --- /dev/null +++ b/render-test/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1536m \ No newline at end of file diff --git a/render-test/android/gradle/wrapper/gradle-wrapper.jar b/render-test/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..8c0fb64a86 Binary files /dev/null and b/render-test/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/render-test/android/gradle/wrapper/gradle-wrapper.properties b/render-test/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..2e4993ee89 --- /dev/null +++ b/render-test/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon Oct 21 12:45:47 EEST 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/render-test/android/gradlew b/render-test/android/gradlew new file mode 100755 index 0000000000..91a7e269e1 --- /dev/null +++ b/render-test/android/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/render-test/android/gradlew.bat b/render-test/android/gradlew.bat new file mode 100644 index 0000000000..aec99730b4 --- /dev/null +++ b/render-test/android/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/render-test/android/render_test_setup.sh b/render-test/android/render_test_setup.sh new file mode 100755 index 0000000000..e34d71df3b --- /dev/null +++ b/render-test/android/render_test_setup.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +adb shell rm -rf /sdcard/render-test +adb shell mkdir /sdcard/render-test +adb shell mkdir /sdcard/render-test/vendor +adb shell mkdir /sdcard/render-test/expected +adb shell mkdir /sdcard/render-test/ignores + +# push test sources +adb push ../../mapbox-gl-js/test/integration/render-tests /sdcard/render-test/mapbox-gl-js/test/integration/render-tests +adb push ../../mapbox-gl-js/test/integration/query-tests /sdcard/render-test/mapbox-gl-js/test/integration/query-tests +adb push ../../mapbox-gl-js/test/integration/tiles /sdcard/render-test/mapbox-gl-js/test/integration/tiles +adb push ../../mapbox-gl-js/test/integration/glyphs /sdcard/render-test/mapbox-gl-js/test/integration/glyphs +adb push ../../mapbox-gl-js/test/integration/styles /sdcard/render-test/mapbox-gl-js/test/integration/styles +adb push ../../mapbox-gl-js/test/integration/tilesets /sdcard/render-test/mapbox-gl-js/test/integration/tilesets +adb push ../../mapbox-gl-js/test/integration/image /sdcard/render-test/mapbox-gl-js/test/integration/image +adb push ../../mapbox-gl-js/test/integration/video /sdcard/render-test/mapbox-gl-js/test/integration/video +adb push ../../vendor/mapbox-gl-styles/styles /sdcard/render-test/vendor/mapbox-gl-styles/styles +adb push ../../vendor/mapbox-gl-styles/sprites /sdcard/render-test/vendor/mapbox-gl-styles/sprites +adb push ../../mapbox-gl-js/test/integration/data /sdcard/render-test/mapbox-gl-js/test/integration/data +adb push ../../mapbox-gl-js/test/integration/geojson /sdcard/render-test/mapbox-gl-js/test/integration/geojson +mkdir sprites +cp -r ../../mapbox-gl-js/test/integration/sprites/ sprites +adb push sprites /sdcard/render-test/mapbox-gl-js/test/integration/sprites +rm -rf sprites + +# push extra expectations +adb push ../../render-test/expected /sdcard/render-test/render-test/expected + +# push default ignore lists +adb shell mkdir /sdcard/render-test/platform +adb shell mkdir /sdcard/render-test/platform/node +adb shell mkdir /sdcard/render-test/platform/node/test +adb push ../../platform/node/test/ignores.json /sdcard/render-test/platform/node/test +adb shell mkdir /sdcard/render-test/render-test +adb push ../../render-test/linux-ignores.json /sdcard/render-test/render-test + +adb shell ls /sdcard/render-test/ \ No newline at end of file diff --git a/render-test/android/settings.gradle b/render-test/android/settings.gradle new file mode 100644 index 0000000000..573abcb323 --- /dev/null +++ b/render-test/android/settings.gradle @@ -0,0 +1,2 @@ +include ':app' + diff --git a/render-test/include/mbgl/render_test.hpp b/render-test/include/mbgl/render_test.hpp index 42a539603d..8a82079bee 100644 --- a/render-test/include/mbgl/render_test.hpp +++ b/render-test/include/mbgl/render_test.hpp @@ -1,9 +1,6 @@ #pragma once - -#include - namespace mbgl { -MBGL_EXPORT int runRenderTests(int argc, char* argv[]); +int runRenderTests(int argc, char* argv[]); } // namespace mbgl diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 69d6981c02..d6ba561950 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -767,7 +767,8 @@ std::string createResultItem(const TestMetadata& metadata, bool hasFailedTests) } } } else { - assert(!metadata.errorMessage.empty()); + // FIXME: there are several places that errorMessage is not filled + // comment out assert(!metadata.errorMessage.empty()); html.append("

Error: " + metadata.errorMessage + "

\n"); } if (metadata.difference != 0.0) { -- cgit v1.2.1 From a4c2cdb507cf35041e4215a2e55eb2b9f9c84ccf Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Tue, 22 Oct 2019 14:45:55 -0400 Subject: [ios] Set xcode properties for cmake. (#15842) * [ios] Set xcode properties for cmake. * Fix Sanitize typo --- next/CMakeLists.txt | 2 +- next/platform/ios/ios.cmake | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index c45c2b8641..524a86e189 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -31,7 +31,7 @@ set(CMAKE_CXX_FLAGS_DEBUGCOVERAGE "${CMAKE_CXX_FLAGS_DEBUG} --coverage") set(CMAKE_C_FLAGS_DEBUGCOVERAGE "${CMAKE_CXX_FLAGS_DEBUG} --coverage") set(CMAKE_CXX_FLAGS_SANITIZE "-DSANITIZE -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=${MBGL_WITH_SANITIZER}") -set(CMAKE_C_FLAGS_SANITIZE "-DSANITEIZE -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=${MBGL_WITH_SANITIZER}") +set(CMAKE_C_FLAGS_SANITIZE "-DSANITIZE -g -O1 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=${MBGL_WITH_SANITIZER}") if(MBGL_WITH_QT) find_package(Qt5Core REQUIRED) diff --git a/next/platform/ios/ios.cmake b/next/platform/ios/ios.cmake index 4558b47b68..10a6839c9d 100644 --- a/next/platform/ios/ios.cmake +++ b/next/platform/ios/ios.cmake @@ -3,6 +3,17 @@ target_compile_definitions( PUBLIC MBGL_USE_GLES2 GLES_SILENCE_DEPRECATION ) +if(NOT DEFINED IOS_DEPLOYMENT_TARGET) + set(IOS_DEPLOYMENT_TARGET "9.0") +endif() + +macro(initialize_ios_target target) + set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IOS_DEPLOYMENT_TARGET}") + set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") + set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE bitcode) + set_target_properties(${target} PROPERTIES XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH $<$:YES>) +endmacro() + set_target_properties(mbgl-core PROPERTIES XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) target_sources( @@ -52,6 +63,9 @@ target_include_directories( include(${PROJECT_SOURCE_DIR}/vendor/icu.cmake) +initialize_ios_target(mbgl-core) +initialize_ios_target(mbgl-vendor-icu) + target_link_libraries( mbgl-core PRIVATE @@ -73,3 +87,5 @@ target_link_libraries( sqlite3 z ) + +unset(IOS_DEPLOYMENT_TARGET CACHE) -- cgit v1.2.1 From b1d048217a08bf38f0c2037d56381e158da7b6bf Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Tue, 22 Oct 2019 22:28:45 +0300 Subject: [node] Exclude node abi 79 (13.x) from build --- cmake/node.cmake | 4 ++-- next/platform/node/CMakeLists.txt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/node.cmake b/cmake/node.cmake index edea4df71b..1e01c8edba 100644 --- a/cmake/node.cmake +++ b/cmake/node.cmake @@ -22,11 +22,11 @@ add_node_module(mbgl-node INSTALL_PATH "lib/{node_abi}/mbgl.node" NAN_VERSION "2.14.0" - # Don't build for Node 4.x, 5.x, 7.x, 9.x, 11.x and 12.x + # Don't build for Node 4.x, 5.x, 7.x, 9.x, 11.x, 12.x and 13.x # See https://nodejs.org/en/download/releases/ for mapping of Node version to ABI number. # Changes to this property should happen in tandem with updates to the version targets # in platform/node/scripts/publish.sh and the "node" engines property in package.json. - EXCLUDE_NODE_ABIS 46 47 51 59 67 72 + EXCLUDE_NODE_ABIS 46 47 51 59 67 72 79 ) target_sources(mbgl-node INTERFACE diff --git a/next/platform/node/CMakeLists.txt b/next/platform/node/CMakeLists.txt index 432979b473..840fab2964 100644 --- a/next/platform/node/CMakeLists.txt +++ b/next/platform/node/CMakeLists.txt @@ -18,6 +18,7 @@ add_node_module( 59 67 72 + 79 ) target_sources( -- cgit v1.2.1 From 99feb9bb306ddf06c228f0b6bbfb88abead6b33a Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 22 Oct 2019 20:30:55 -0400 Subject: [core] fix collisions with icon-text-fit and variable placement (#15828) port 61a61a1982cb8c637d467f91da5b0817a61a9de6 --- mapbox-gl-js | 2 +- src/mbgl/text/placement.cpp | 59 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index 2dbbf63490..e18977bb07 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 2dbbf634906dc1b02b48cb740dadb6de16348475 +Subproject commit e18977bb0771b981c47404f4b8711c456a487d5f diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 8b0a3975fc..4c18e3ba25 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -220,7 +220,6 @@ void Placement::placeBucket( if (horizontalTextIndex) { const PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex); const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol); - const CollisionFeature& textCollisionFeature = symbolInstance.textCollisionFeature; const auto updatePreviousOrientationIfNotPlaced = [&](bool isPlaced) { if (bucket.allowVerticalPlacement && !isPlaced && getPrevPlacement()) { @@ -282,7 +281,8 @@ void Placement::placeBucket( placeText = placed.first; offscreen &= placed.second; - } else if (!textCollisionFeature.alongLine && !textCollisionFeature.boxes.empty()) { + } else if (!symbolInstance.textCollisionFeature.alongLine && + !symbolInstance.textCollisionFeature.boxes.empty()) { // If this symbol was in the last placement, shift the previously used // anchor to the front of the anchor list, only if the previous anchor // is still in the anchor list. @@ -305,8 +305,13 @@ void Placement::placeBucket( } } - const auto placeFeatureForVariableAnchors = [&] (const CollisionFeature& collisionFeature, style::TextWritingModeType orientation) { - const CollisionBox& textBox = collisionFeature.boxes[0]; + const bool doVariableIconPlacement = + hasIconTextFit && !iconAllowOverlap && symbolInstance.placedIconIndex; + + const auto placeFeatureForVariableAnchors = [&](const CollisionFeature& textCollisionFeature, + style::TextWritingModeType orientation, + const CollisionFeature& iconCollisionFeature) { + const CollisionBox& textBox = textCollisionFeature.boxes[0]; const float width = textBox.x2 - textBox.x1; const float height = textBox.y2 - textBox.y1; const float textBoxScale = symbolInstance.textBoxScale; @@ -323,12 +328,40 @@ void Placement::placeBucket( } textBoxes.clear(); - placedFeature = collisionIndex.placeFeature(collisionFeature, shift, - posMatrix, mat4(), pixelRatio, - placedSymbol, scale, fontSize, + placedFeature = collisionIndex.placeFeature(textCollisionFeature, + shift, + posMatrix, + mat4(), + pixelRatio, + placedSymbol, + scale, + fontSize, allowOverlap, pitchWithMap, - params.showCollisionBoxes, avoidEdges, collisionGroup.second, textBoxes); + params.showCollisionBoxes, + avoidEdges, + collisionGroup.second, + textBoxes); + + if (doVariableIconPlacement) { + auto placedIconFeature = collisionIndex.placeFeature(iconCollisionFeature, + shift, + posMatrix, + iconLabelPlaneMatrix, + pixelRatio, + placedSymbol, + scale, + fontSize, + iconAllowOverlap, + pitchWithMap, + params.showCollisionBoxes, + avoidEdges, + collisionGroup.second, + iconBoxes); + iconBoxes.clear(); + if (!placedIconFeature.first) continue; + } + if (placedFeature.first) { assert(symbolInstance.crossTileID != 0u); optional prevAnchor; @@ -366,12 +399,18 @@ void Placement::placeBucket( }; const auto placeHorizontal = [&] { - return placeFeatureForVariableAnchors(symbolInstance.textCollisionFeature, style::TextWritingModeType::Horizontal); + return placeFeatureForVariableAnchors(symbolInstance.textCollisionFeature, + style::TextWritingModeType::Horizontal, + symbolInstance.iconCollisionFeature); }; const auto placeVertical = [&] { if (bucket.allowVerticalPlacement && !placed.first && symbolInstance.verticalTextCollisionFeature) { - return placeFeatureForVariableAnchors(*symbolInstance.verticalTextCollisionFeature, style::TextWritingModeType::Vertical); + return placeFeatureForVariableAnchors(*symbolInstance.verticalTextCollisionFeature, + style::TextWritingModeType::Vertical, + symbolInstance.verticalIconCollisionFeature + ? *symbolInstance.verticalIconCollisionFeature + : symbolInstance.iconCollisionFeature); } return std::pair{false, false}; }; -- cgit v1.2.1 From 2385f4cd86261cdfc6253de5fed217bfc06fa6c8 Mon Sep 17 00:00:00 2001 From: zmiao Date: Wed, 23 Oct 2019 12:04:23 +0300 Subject: [render-test] Add configurable rootPath, ignorePath via CLI arguments (#15832) * [render-test] Add configurable path via CLI arguments * [render-test] Change ignore path config --- next/platform/linux/linux.cmake | 6 +- next/platform/macos/macos.cmake | 4 +- render-test/parser.cpp | 210 +++++++++++++++++++++++++--------------- render-test/parser.hpp | 16 +-- render-test/render_test.cpp | 13 +-- render-test/runner.cpp | 18 ++-- render-test/runner.hpp | 9 +- 7 files changed, 167 insertions(+), 109 deletions(-) diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 6a68a1f2d2..5bde30a61a 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -149,5 +149,9 @@ add_test( WORKING_DIRECTORY ${MBGL_ROOT} ) -add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test-runner tests --rootPath=render-test WORKING_DIRECTORY ${MBGL_ROOT}) +add_test( + NAME mbgl-render-test-probes + COMMAND mbgl-render-test-runner tests --rootPath=${MBGL_ROOT}/render-test + WORKING_DIRECTORY ${MBGL_ROOT} +) add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests WORKING_DIRECTORY ${MBGL_ROOT}) diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index 71e53c474a..cfabcb1cfa 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -218,8 +218,8 @@ add_test( COMMAND mbgl-render-test-runner tests - --rootPath=render-test - --expectationsPath=render-test/tests/mac + --rootPath=${MBGL_ROOT}/render-test + --expectationsPath=tests/mac WORKING_DIRECTORY ${MBGL_ROOT} ) diff --git a/render-test/parser.cpp b/render-test/parser.cpp index d6ba561950..f410ffa860 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -96,8 +96,11 @@ std::string prependFileScheme(const std::string &url) { return fileScheme + url; } -mbgl::optional getVendorPath(const std::string& url, const std::regex& regex, bool glyphsPath = false) { - static const mbgl::filesystem::path vendorPath(std::string(TEST_RUNNER_ROOT_PATH) + "/vendor/"); +mbgl::optional getVendorPath(const std::string& url, + const std::regex& regex, + const std::string& testRootPath, + bool glyphsPath = false) { + static const mbgl::filesystem::path vendorPath = getValidPath(testRootPath, std::string("vendor/")); mbgl::filesystem::path file = std::regex_replace(url, regex, vendorPath.string()); if (mbgl::filesystem::exists(file.parent_path())) { @@ -111,8 +114,13 @@ mbgl::optional getVendorPath(const std::string& url, const std::reg return {}; } -mbgl::optional getIntegrationPath(const std::string& url, const std::string& parent, const std::regex& regex, bool glyphsPath = false) { - static const mbgl::filesystem::path integrationPath(std::string(TEST_RUNNER_ROOT_PATH) + "/mapbox-gl-js/test/integration/"); +mbgl::optional getIntegrationPath(const std::string& url, + const std::string& parent, + const std::regex& regex, + const std::string& testRootPath, + bool glyphsPath = false) { + static const mbgl::filesystem::path integrationPath = + getValidPath(testRootPath, std::string("mapbox-gl-js/test/integration/")); mbgl::filesystem::path file = std::regex_replace(url, regex, integrationPath.string() + parent); if (mbgl::filesystem::exists(file.parent_path())) { @@ -126,46 +134,48 @@ mbgl::optional getIntegrationPath(const std::string& url, const std return {}; } -mbgl::optional localizeLocalURL(const std::string& url, bool glyphsPath = false) { - static const std::regex regex { "local://" }; - if (auto vendorPath = getVendorPath(url, regex, glyphsPath)) { +mbgl::optional localizeLocalURL(const std::string& url, + const std::string& testRootPath, + bool glyphsPath = false) { + static const std::regex regex{"local://"}; + if (auto vendorPath = getVendorPath(url, regex, testRootPath, glyphsPath)) { return vendorPath; } else { - return getIntegrationPath(url, "", regex, glyphsPath); + return getIntegrationPath(url, "", regex, testRootPath, glyphsPath); } } -mbgl::optional localizeHttpURL(const std::string& url) { - static const std::regex regex { "http://localhost:2900" }; - if (auto vendorPath = getVendorPath(url, regex)) { +mbgl::optional localizeHttpURL(const std::string& url, const std::string& testRootPath) { + static const std::regex regex{"http://localhost:2900"}; + if (auto vendorPath = getVendorPath(url, regex, testRootPath)) { return vendorPath; } else { - return getIntegrationPath(url, "", regex); + return getIntegrationPath(url, "", regex, testRootPath); } } -mbgl::optional localizeMapboxSpriteURL(const std::string& url) { - static const std::regex regex { "mapbox://" }; - return getIntegrationPath(url, "", regex); +mbgl::optional localizeMapboxSpriteURL(const std::string& url, const std::string& testRootPath) { + static const std::regex regex{"mapbox://"}; + return getIntegrationPath(url, "", regex, testRootPath); } -mbgl::optional localizeMapboxFontsURL(const std::string& url) { - static const std::regex regex { "mapbox://fonts" }; - return getIntegrationPath(url, "glyphs/", regex, true); +mbgl::optional localizeMapboxFontsURL(const std::string& url, const std::string& testRootPath) { + static const std::regex regex{"mapbox://fonts"}; + return getIntegrationPath(url, "glyphs/", regex, testRootPath, true); } -mbgl::optional localizeMapboxTilesURL(const std::string& url) { - static const std::regex regex { "mapbox://" }; - if (auto vendorPath = getVendorPath(url, regex)) { +mbgl::optional localizeMapboxTilesURL(const std::string& url, const std::string& testRootPath) { + static const std::regex regex{"mapbox://"}; + if (auto vendorPath = getVendorPath(url, regex, testRootPath)) { return vendorPath; } else { - return getIntegrationPath(url, "tiles/", regex); + return getIntegrationPath(url, "tiles/", regex, testRootPath); } } -mbgl::optional localizeMapboxTilesetURL(const std::string& url) { - static const std::regex regex { "mapbox://" }; - return getIntegrationPath(url, "tilesets/", regex); +mbgl::optional localizeMapboxTilesetURL(const std::string& url, const std::string& testRootPath) { + static const std::regex regex{"mapbox://"}; + return getIntegrationPath(url, "tilesets/", regex, testRootPath); } void writeJSON(rapidjson::PrettyWriter& writer, const mbgl::Value& value) { @@ -195,6 +205,33 @@ void writeJSON(rapidjson::PrettyWriter& writer, const m } // namespace +static const mbgl::filesystem::path DefaultRootPath{std::string(TEST_RUNNER_ROOT_PATH)}; + +const mbgl::filesystem::path getValidPath(const std::string& basePath, const std::string& subPath) { + auto filePath = mbgl::filesystem::path(basePath) / subPath; + if (mbgl::filesystem::exists(filePath)) { + return filePath; + } + // Fall back to check default path + filePath = DefaultRootPath / subPath; + if (mbgl::filesystem::exists(filePath)) { + return filePath; + } + mbgl::Log::Warning(mbgl::Event::General, "Failed to find path: %s", subPath.c_str()); + return mbgl::filesystem::path{}; +} + +/// Returns path of the render test cases directory. +const std::string getTestPath(const std::string& rootTestPath) { + // Check if sub-directory exits or not + auto testBasePath = mbgl::filesystem::path(rootTestPath) / ("mapbox-gl-js/test/integration"); + if (mbgl::filesystem::exists(testBasePath)) { + return testBasePath.string(); + } + // Use root test path for further processing + return rootTestPath; +} + std::string toJSON(const mbgl::Value& value, unsigned indent, bool singleLine) { rapidjson::StringBuffer buffer; rapidjson::PrettyWriter writer(buffer); @@ -373,17 +410,16 @@ ArgumentsTuple parseArguments(int argc, char** argv) { args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", { 'h', "help" }); - args::Flag recycleMapFlag(argumentParser, "recycle map", "Toggle reusing the map object", - { 'r', "recycle-map" }); - args::Flag shuffleFlag(argumentParser, "shuffle", "Toggle shuffling the tests order", - { 's', "shuffle" }); + args::Flag recycleMapFlag(argumentParser, "recycle map", "Toggle reusing the map object", {'r', "recycle-map"}); + args::Flag shuffleFlag(argumentParser, "shuffle", "Toggle shuffling the tests order", {'s', "shuffle"}); args::ValueFlag seedValue(argumentParser, "seed", "Shuffle seed (default: random)", { "seed" }); - args::ValueFlag testPathValue(argumentParser, "rootPath", "Test root rootPath", - { 'p', "rootPath" }); + args::ValueFlag testPathValue(argumentParser, "rootPath", "Test root rootPath", {'p', "rootPath"}); args::ValueFlag testFilterValue(argumentParser, "filter", "Test filter regex", {'f', "filter"}); args::ValueFlag expectationsPathValue( argumentParser, "expectationsPath", "Test expectations path", {'e', "expectationsPath"}); + args::ValueFlag ignoresPathValue( + argumentParser, "ignoresPath", "Test ignore list path", {'i', "ignoresPath"}); args::PositionalList testNameValues(argumentParser, "URL", "Test name(s)"); try { @@ -410,14 +446,16 @@ ArgumentsTuple parseArguments(int argc, char** argv) { exit(3); } - mbgl::filesystem::path rootPath {testPathValue ? args::get(testPathValue) : TestRunner::getBasePath()}; + const auto testRootPath = testPathValue ? args::get(testPathValue) : std::string{TEST_RUNNER_ROOT_PATH}; + mbgl::filesystem::path rootPath{testRootPath}; if (!mbgl::filesystem::exists(rootPath)) { - mbgl::Log::Error(mbgl::Event::General, "Provided rootPath '%s' does not exist.", rootPath.string().c_str()); + mbgl::Log::Error( + mbgl::Event::General, "Provided test rootPath '%s' does not exist.", rootPath.string().c_str()); exit(4); } std::vector expectationsPaths; if (expectationsPathValue) { - auto expectationsPath = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH) / args::get(expectationsPathValue); + auto expectationsPath = mbgl::filesystem::path(testRootPath) / args::get(expectationsPathValue); if (!mbgl::filesystem::exists(expectationsPath)) { mbgl::Log::Error(mbgl::Event::General, "Provided expectationsPath '%s' does not exist.", @@ -427,13 +465,25 @@ ArgumentsTuple parseArguments(int argc, char** argv) { expectationsPaths.emplace_back(std::move(expectationsPath)); } + std::string ignoresPath{}; + if (ignoresPathValue) { + auto path = mbgl::filesystem::path(testRootPath) / args::get(ignoresPathValue); + if (!mbgl::filesystem::exists(path)) { + mbgl::Log::Error( + mbgl::Event::General, "Provided ignore list path '%s' does not exist.", path.string().c_str()); + exit(6); + } + ignoresPath = path.string(); + } + std::vector paths; + auto testBasePath = mbgl::filesystem::path(getTestPath(testRootPath)); for (const auto& id : args::get(testNameValues)) { - paths.emplace_back(rootPath / id); + paths.emplace_back(testBasePath / id); } if (paths.empty()) { - paths.emplace_back(rootPath); + paths.emplace_back(testBasePath); } // Recursively traverse through the test paths and collect test directories containing "style.json". @@ -456,30 +506,33 @@ ArgumentsTuple parseArguments(int argc, char** argv) { } } - return ArgumentsTuple { - recycleMapFlag ? args::get(recycleMapFlag) : false, - shuffleFlag ? args::get(shuffleFlag) : false, seedValue ? args::get(seedValue) : 1u, - testPathValue ? args::get(testPathValue) : TestRunner::getBasePath(), - std::move(testPaths) - }; + return ArgumentsTuple{recycleMapFlag ? args::get(recycleMapFlag) : false, + shuffleFlag ? args::get(shuffleFlag) : false, + seedValue ? args::get(seedValue) : 1u, + testRootPath, + ignoresPath, + std::move(testPaths)}; } -std::vector> parseIgnores() { +std::vector> parseIgnores(const std::string& testRootPath, + const std::string& ignoresPath) { std::vector> ignores; - - auto mainIgnoresPath = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("platform/node/test/ignores.json"); + auto mainIgnoresPath = getValidPath(testRootPath, "platform/node/test/ignores.json"); mbgl::filesystem::path platformSpecificIgnores; - mbgl::filesystem::path ownTestsIgnores = - mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("render-test/tests/should-fail.json"); + mbgl::filesystem::path ownTestsIgnores = getValidPath(testRootPath, "render-test/tests/should-fail.json"); #ifdef __APPLE__ - platformSpecificIgnores = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("render-test/mac-ignores.json"); + platformSpecificIgnores = getValidPath(testRootPath, "render-test/mac-ignores.json"); #elif __linux__ - platformSpecificIgnores = mbgl::filesystem::path(TEST_RUNNER_ROOT_PATH).append("render-test/linux-ignores.json"); + platformSpecificIgnores = getValidPath(testRootPath, "render-test/linux-ignores.json"); #endif std::vector ignoresPaths = {mainIgnoresPath, platformSpecificIgnores, ownTestsIgnores}; + + if (!ignoresPath.empty()) { + ignoresPaths.emplace_back(ignoresPath); + } for (const auto& path : ignoresPaths) { auto maybeIgnores = readJson(path); if (!maybeIgnores.is()) { @@ -586,7 +639,7 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { return result; } -TestMetadata parseTestMetadata(const TestPaths& paths) { +TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRootPath) { TestMetadata metadata; metadata.paths = paths; @@ -597,11 +650,10 @@ TestMetadata parseTestMetadata(const TestPaths& paths) { } metadata.document = std::move(maybeJson.get()); - localizeStyleURLs(metadata.document, metadata.document); + localizeStyleURLs(metadata.document, metadata.document, testRootPath); if (!metadata.document.HasMember("metadata")) { - mbgl::Log::Warning(mbgl::Event::ParseStyle, "Style has no 'metadata': %s", - paths.stylePath.c_str()); + mbgl::Log::Warning(mbgl::Event::ParseStyle, "Style has no 'metadata': %s", paths.stylePath.c_str()); return metadata; } @@ -861,21 +913,21 @@ std::string createResultPage(const TestStatistics& stats, const std::vector(path, document.GetAllocator()); } } @@ -885,9 +937,9 @@ void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document) { static const std::string video("video"); mbgl::JSValue& urlValue = root["url"]; - const std::string path = prependFileScheme(localizeMapboxTilesetURL(urlValue.GetString()) - .value_or(localizeLocalURL(urlValue.GetString()) - .value_or(urlValue.GetString()))); + const std::string path = prependFileScheme( + localizeMapboxTilesetURL(urlValue.GetString(), testRootPath) + .value_or(localizeLocalURL(urlValue.GetString(), testRootPath).value_or(urlValue.GetString()))); urlValue.Set(path, document.GetAllocator()); if (root["type"].GetString() != image && root["type"].GetString() != video) { @@ -906,43 +958,45 @@ void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document) { mbgl::JSValue& tilesValue = root["tiles"]; assert(tilesValue.IsArray()); for (auto& tileValue : tilesValue.GetArray()) { - const std::string path = prependFileScheme(localizeMapboxTilesURL(tileValue.GetString()) - .value_or(localizeLocalURL(tileValue.GetString()) - .value_or(localizeHttpURL(tileValue.GetString()) - .value_or(tileValue.GetString())))); + const std::string path = + prependFileScheme(localizeMapboxTilesURL(tileValue.GetString(), testRootPath) + .value_or(localizeLocalURL(tileValue.GetString(), testRootPath) + .value_or(localizeHttpURL(tileValue.GetString(), testRootPath) + .value_or(tileValue.GetString())))); tileValue.Set(path, document.GetAllocator()); } } if (root.HasMember("data") && root["data"].IsString()) { mbgl::JSValue& dataValue = root["data"]; - const std::string path = prependFileScheme(localizeLocalURL(dataValue.GetString()) - .value_or(dataValue.GetString())); + const std::string path = + prependFileScheme(localizeLocalURL(dataValue.GetString(), testRootPath).value_or(dataValue.GetString())); dataValue.Set(path, document.GetAllocator()); } } -void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document) { +void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document, const std::string& testRootPath) { if (root.HasMember("sources")) { mbgl::JSValue& sourcesValue = root["sources"]; for (auto& sourceProperty : sourcesValue.GetObject()) { - localizeSourceURLs(sourceProperty.value, document); + localizeSourceURLs(sourceProperty.value, document, testRootPath); } } if (root.HasMember("glyphs")) { mbgl::JSValue& glyphsValue = root["glyphs"]; - const std::string path = prependFileScheme(localizeMapboxFontsURL(glyphsValue.GetString()) - .value_or(localizeLocalURL(glyphsValue.GetString(), true) - .value_or(glyphsValue.GetString()))); + const std::string path = prependFileScheme( + localizeMapboxFontsURL(glyphsValue.GetString(), testRootPath) + .value_or( + localizeLocalURL(glyphsValue.GetString(), testRootPath, true).value_or(glyphsValue.GetString()))); glyphsValue.Set(path, document.GetAllocator()); } if (root.HasMember("sprite")) { mbgl::JSValue& spriteValue = root["sprite"]; - const std::string path = prependFileScheme(localizeMapboxSpriteURL(spriteValue.GetString()) - .value_or(localizeLocalURL(spriteValue.GetString()) - .value_or(spriteValue.GetString()))); + const std::string path = prependFileScheme( + localizeMapboxSpriteURL(spriteValue.GetString(), testRootPath) + .value_or(localizeLocalURL(spriteValue.GetString(), testRootPath).value_or(spriteValue.GetString()))); spriteValue.Set(path, document.GetAllocator()); } } diff --git a/render-test/parser.hpp b/render-test/parser.hpp index 3c857b7e1e..1985b9cffc 100644 --- a/render-test/parser.hpp +++ b/render-test/parser.hpp @@ -12,7 +12,7 @@ using ErrorMessage = std::string; using JSONReply = mbgl::variant; -using ArgumentsTuple = std::tuple>; +using ArgumentsTuple = std::tuple>; JSONReply readJson(const mbgl::filesystem::path&); std::string serializeJsonValue(const mbgl::JSValue&); @@ -23,17 +23,21 @@ std::vector readExpectedJSONEntries(const mbgl::filesystem::path& b TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path); +const std::string getTestPath(const std::string& rootTestPath); +const mbgl::filesystem::path getValidPath(const std::string& basePath, const std::string& subPath); + ArgumentsTuple parseArguments(int argc, char** argv); -std::vector> parseIgnores(); +std::vector> parseIgnores(const std::string& testRootPath, + const std::string& ignoresPath); -TestMetadata parseTestMetadata(const TestPaths& paths); +TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRootPath); std::string createResultPage(const TestStatistics&, const std::vector&, bool shuffle, uint32_t seed); -std::string localizeURL(const std::string& url); +std::string localizeURL(const std::string& url, const std::string& testPath); std::string toJSON(const mbgl::Value& value, unsigned indent, bool singleLine); std::string toJSON(const std::vector& features, unsigned indent, bool singleLine); -void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document); -void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document); \ No newline at end of file +void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document, const std::string& testPath); +void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document, const std::string& testPath); diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index df1658265a..2cf3f5fd65 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -44,12 +44,12 @@ int runRenderTests(int argc, char** argv) { bool shuffle; uint32_t seed; std::string testRootPath; + std::string ignoresPath; std::vector testPaths; - std::tie(recycleMap, shuffle, seed, testRootPath, testPaths) = parseArguments(argc, argv); - const std::string::size_type rootLength = testRootPath.length(); + std::tie(recycleMap, shuffle, seed, testRootPath, ignoresPath, testPaths) = parseArguments(argc, argv); - const auto ignores = parseIgnores(); + const auto ignores = parseIgnores(testRootPath, ignoresPath); if (shuffle) { printf(ANSI_COLOR_YELLOW "Shuffle seed: %d" ANSI_COLOR_RESET "\n", seed); @@ -60,7 +60,7 @@ int runRenderTests(int argc, char** argv) { } mbgl::util::RunLoop runLoop; - TestRunner runner; + TestRunner runner(testRootPath); std::vector metadatas; metadatas.reserve(testPaths.size()); @@ -68,7 +68,7 @@ int runRenderTests(int argc, char** argv) { TestStatistics stats; for (auto& testPath : testPaths) { - TestMetadata metadata = parseTestMetadata(testPath); + TestMetadata metadata = parseTestMetadata(testPath, testRootPath); if (!recycleMap) { runner.reset(); @@ -78,6 +78,7 @@ int runRenderTests(int argc, char** argv) { std::string& status = metadata.status; std::string& color = metadata.color; + const std::string::size_type rootLength = getTestPath(testRootPath).length(); id = testPath.defaultExpectations(); id = id.substr(rootLength + 1, id.length() - rootLength - 2); @@ -166,4 +167,4 @@ int runRenderTests(int argc, char** argv) { return stats.failedTests + stats.erroredTests == 0 ? 0 : 1; } -} // namespace mbgl \ No newline at end of file +} // namespace mbgl diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 46b890b76c..4c0967a9e9 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -57,12 +57,6 @@ public: bool idle; }; -// static -const std::string& TestRunner::getBasePath() { - const static std::string result = std::string(TEST_RUNNER_ROOT_PATH).append("/mapbox-gl-js/test/integration"); - return result; -} - // static gfx::HeadlessBackend::SwapBehaviour swapBehavior(MapMode mode) { return mode == MapMode::Continuous ? gfx::HeadlessBackend::SwapBehaviour::Flush @@ -107,6 +101,8 @@ std::string simpleDiff(const Value& result, const Value& expected) { return diff.str(); } +TestRunner::TestRunner(const std::string& testRootPath_) : maps(), testRootPath(testRootPath_) {} + bool TestRunner::checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, std::vector&& features, TestMetadata& metadata) { @@ -491,7 +487,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { std::string imagePath = operationArray[2].GetString(); imagePath.erase(std::remove(imagePath.begin(), imagePath.end(), '"'), imagePath.end()); - const mbgl::filesystem::path filePath(std::string(TEST_RUNNER_ROOT_PATH) + "/mapbox-gl-js/test/integration/" + imagePath); + const mbgl::filesystem::path filePath = mbgl::filesystem::path(getTestPath(testRootPath)) / imagePath; mbgl::optional maybeImage = mbgl::util::readFile(filePath.string()); if (!maybeImage) { @@ -511,15 +507,15 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { // setStyle assert(operationArray.Size() >= 2u); if (operationArray[1].IsString()) { - std::string stylePath = localizeURL(operationArray[1].GetString()); + std::string stylePath = localizeURL(operationArray[1].GetString(), testRootPath); auto maybeStyle = readJson(stylePath); if (maybeStyle.is()) { auto& style = maybeStyle.get(); - localizeStyleURLs((mbgl::JSValue&)style, style); + localizeStyleURLs((mbgl::JSValue&)style, style, testRootPath); map.getStyle().loadJSON(serializeJsonValue(style)); } } else { - localizeStyleURLs(operationArray[1], metadata.document); + localizeStyleURLs(operationArray[1], metadata.document, testRootPath); map.getStyle().loadJSON(serializeJsonValue(operationArray[1])); } } else if (operationArray[0].GetString() == setCenterOp) { @@ -620,7 +616,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(operationArray[1].IsString()); assert(operationArray[2].IsObject()); - localizeSourceURLs(operationArray[2], metadata.document); + localizeSourceURLs(operationArray[2], metadata.document, testRootPath); mbgl::style::conversion::Error error; auto converted = mbgl::style::conversion::convert>(operationArray[2], error, operationArray[1].GetString()); diff --git a/render-test/runner.hpp b/render-test/runner.hpp index 6aba2d2391..3efd17bf1e 100644 --- a/render-test/runner.hpp +++ b/render-test/runner.hpp @@ -4,6 +4,7 @@ #include #include +#include class TestRunnerMapObserver; struct TestMetadata; @@ -11,13 +12,10 @@ struct TestMetadata; class TestRunner { public: TestRunner() = default; - + explicit TestRunner(const std::string& testRootPath); bool run(TestMetadata&); void reset(); - /// Returns path of the render tests root directory. - static const std::string& getBasePath(); - private: bool runOperations(const std::string& key, TestMetadata&); bool checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, @@ -34,4 +32,5 @@ private: mbgl::Map map; }; std::unordered_map> maps; -}; \ No newline at end of file + std::string testRootPath{TEST_RUNNER_ROOT_PATH}; +}; -- cgit v1.2.1 From 1cfd0c4e92df6d0a4209b3e6517da6b7ca01af46 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Wed, 23 Oct 2019 00:47:33 +0300 Subject: [build] Bump CI docker image This version includes gcloud, needed to run android firebase tests. --- circle.yml | 2 +- scripts/ci/Dockerfile | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index e1923498a7..ca732d200c 100644 --- a/circle.yml +++ b/circle.yml @@ -183,7 +183,7 @@ executors: ubuntu-disco: docker: # FIXME: Move the image to mbgl/ - - image: tmpsantos/mbgl_ci:1.5 + - image: tmpsantos/mbgl_ci:1.6 resource_class: xlarge working_directory: /src environment: diff --git a/scripts/ci/Dockerfile b/scripts/ci/Dockerfile index 648581044f..09ae07997d 100644 --- a/scripts/ci/Dockerfile +++ b/scripts/ci/Dockerfile @@ -40,7 +40,7 @@ RUN set -eu && apt-get install -y \ software-properties-common \ xvfb -RUN pip3 install cmake_format +RUN pip3 install cmake-format==0.5.5 # Linux dependencies RUN set -eu && apt-get install -y \ @@ -103,6 +103,12 @@ RUN set -eu \ "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2" \ "cmake;3.10.2.4988404" +# Install gcloud for Firebase testing +RUN set -eu \ + && echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \ + && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - \ + && apt-get update -y && apt-get install google-cloud-sdk -y + # Configure ccache RUN set -eu && /usr/sbin/update-ccache-symlinks -- cgit v1.2.1 From a1aa3b0e086ac31fd59cc870acc72f42be919679 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 23 Oct 2019 17:46:19 -0700 Subject: fix linux node platform publishing --- circle.yml | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index ca732d200c..e411d21267 100644 --- a/circle.yml +++ b/circle.yml @@ -123,7 +123,7 @@ workflows: jobs: # # Naming convention: {platform}-{additional description}-{build type} - # - {platform} is the client platform/framework, which may differ from + # - {platform} is the client platform/framework, which may differ from # the build platform. Specify both if applicable, e.g., "qt5-macos". # - {additional description} optionally describes the compiler or other # unique aspect of the build environment. @@ -143,6 +143,10 @@ workflows: filters: tags: only: /android-v.*/ + - node-linux-release: + filters: + tags: + only: /node-.*/ - node-macos-release: filters: tags: @@ -556,6 +560,19 @@ commands: name: Run node tests command: make test-node + run-node-linux-tests: + parameters: + node_version: + type: string + default: 10 + steps: + - run: + name: Run node tests + command: | + . "$NVM_DIR/nvm.sh" && nvm use << parameters.node_version >> + xvfb-run --server-args="-screen 0 1024x768x24" \ + logbt -- apitrace trace --api=egl -v make test-node + run-unit-tests: steps: - run: @@ -930,6 +947,24 @@ jobs: cd misc/buck buck build mapbox-gl-native:android-core +# ------------------------------------------------------------------------------ + node-linux-release: + docker: + - image: mbgl/linux-clang-3.9:2077f965ed + resource_class: large + working_directory: /src + environment: + LIBSYSCONFCPUS: 4 + JOBS: 4 + BUILDTYPE: RelWithDebInfo + WITH_EGL: 1 + steps: + - install-dependencies + - build-node + - save-dependencies + - run-node-linux-tests + - publish-node-package + # ------------------------------------------------------------------------------ node-macos-release: macos: -- cgit v1.2.1 From 744102d95524f6ae3b451f9cfd726651008fcd6b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 23 Oct 2019 18:42:48 -0700 Subject: back to v8 --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index e411d21267..11954ccf6d 100644 --- a/circle.yml +++ b/circle.yml @@ -564,7 +564,7 @@ commands: parameters: node_version: type: string - default: 10 + default: v8 steps: - run: name: Run node tests -- cgit v1.2.1 From 4fb75ba32cf98f04ad817ff51407c0a428202a7a Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Wed, 23 Oct 2019 17:21:38 -0400 Subject: [core] avoid edges for labels that use text-variable-anchors to prevent clipped labels in rendered image tiles. --- src/mbgl/text/placement.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 4c18e3ba25..ecc8f93032 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -164,12 +164,12 @@ void Placement::placeBucket( auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); optional avoidEdges; - if (mapMode == MapMode::Tile && - (layout.get() || - layout.get() == style::SymbolPlacementType::Line)) { + if (mapMode == MapMode::Tile && (layout.get() || + layout.get() == style::SymbolPlacementType::Line || + !layout.get().empty())) { avoidEdges = collisionIndex.projectTileBoundaries(posMatrix); } - + const bool textAllowOverlap = layout.get(); const bool iconAllowOverlap = layout.get(); // This logic is similar to the "defaultOpacityState" logic below in updateBucketOpacities -- cgit v1.2.1 From 424cf2020700f4e8ff4cef6906c5ed85674a1250 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 24 Oct 2019 13:13:01 +0300 Subject: [core] Revert coalescing requests to the client for the same missing image --- src/mbgl/renderer/image_manager.cpp | 73 +++++++++++++----------------------- src/mbgl/renderer/image_manager.hpp | 17 ++++----- test/renderer/image_manager.test.cpp | 24 ------------ 3 files changed, 34 insertions(+), 80 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 7b51fb9a2e..d001084f92 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -138,9 +138,8 @@ void ImageManager::removeRequestor(ImageRequestor& requestor) { void ImageManager::notifyIfMissingImageAdded() { for (auto it = missingImageRequestors.begin(); it != missingImageRequestors.end();) { - ImageRequestor& requestor = *it->first; - if (!requestor.hasPendingRequests()) { - notify(requestor, it->second); + if (it->second.callbacks.empty()) { + notify(*it->first, it->second.pair); it = missingImageRequestors.erase(it); } else { ++it; @@ -170,56 +169,38 @@ void ImageManager::reduceMemoryUseIfCacheSizeExceedsLimit() { } void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageRequestPair& pair) { - ImageDependencies missingDependencies; - + std::vector missingImages; + missingImages.reserve(pair.first.size()); for (const auto& dependency : pair.first) { if (images.find(dependency.first) == images.end()) { - missingDependencies.emplace(dependency); + missingImages.push_back(dependency.first); } } - if (!missingDependencies.empty()) { + if (!missingImages.empty()) { ImageRequestor* requestorPtr = &requestor; - assert(!missingImageRequestors.count(requestorPtr)); - missingImageRequestors.emplace(requestorPtr, pair); - for (const auto& dependency : missingDependencies) { - const std::string& missingImage = dependency.first; - assert(observer != nullptr); + auto emplaced = missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair { pair, {} }); + assert(emplaced.second); - auto existingRequestorsIt = requestedImages.find(missingImage); - if (existingRequestorsIt != requestedImages.end()) { // Already asked client about this image. - std::set& existingRequestors = existingRequestorsIt->second; - if (!existingRequestors.empty() && - (*existingRequestors.begin()) - ->hasPendingRequest(missingImage)) { // Still waiting for the client response for this image. - requestorPtr->addPendingRequest(missingImage); - existingRequestors.emplace(requestorPtr); - continue; - } - // Unlike icons, pattern changes are not caught - // with style-diff meaning that the existing request - // could be from the previous style and we cannot - // coalesce requests for them. - if (dependency.second != ImageType::Pattern) { - continue; - } - } - requestedImages[missingImage].emplace(requestorPtr); - requestor.addPendingRequest(missingImage); - - auto removePendingRequests = [this, missingImage] { - auto existingRequest = requestedImages.find(missingImage); - if (existingRequest == requestedImages.end()) { - return; - } - - for (auto* req : existingRequest->second) { - req->removePendingRequest(missingImage); - } - }; - observer->onStyleImageMissing(missingImage, - Scheduler::GetCurrent()->bindOnce(std::move(removePendingRequests))); + for (const auto& missingImage : missingImages) { + assert(observer != nullptr); + requestedImages[missingImage].emplace(&requestor); + auto callback = std::make_unique( + *Scheduler::GetCurrent(), + [this, requestorPtr, missingImage] { + auto requestorIt = missingImageRequestors.find(requestorPtr); + if (requestorIt != missingImageRequestors.end()) { + assert(requestorIt->second.callbacks.find(missingImage) != requestorIt->second.callbacks.end()); + requestorIt->second.callbacks.erase(missingImage); + } + }); + + auto actorRef = callback->self(); + emplaced.first->second.callbacks.emplace(missingImage, std::move(callback)); + observer->onStyleImageMissing(missingImage, [actorRef] { + actorRef.invoke(&Callback::operator()); + }); } } else { // Associate requestor with an image that was provided by the client. @@ -249,7 +230,7 @@ void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pai } } - requestor.onImagesAvailable(std::move(iconMap), std::move(patternMap), std::move(versionMap), pair.second); + requestor.onImagesAvailable(iconMap, patternMap, std::move(versionMap), pair.second); } void ImageManager::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index 5ed6e237f0..9097418681 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -58,7 +58,13 @@ private: bool loaded = false; std::map requestors; - std::map missingImageRequestors; + using Callback = std::function; + using ActorCallback = Actor; + struct MissingImageRequestPair { + ImageRequestPair pair; + std::map> callbacks; + }; + std::map missingImageRequestors; std::map> requestedImages; std::size_t requestedImagesCacheSize = 0ul; ImageMap images; @@ -71,17 +77,8 @@ public: explicit ImageRequestor(ImageManager&); virtual ~ImageRequestor(); virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) = 0; - - void addPendingRequest(const std::string& imageId) { pendingRequests.insert(imageId); } - bool hasPendingRequest(const std::string& imageId) const { return pendingRequests.count(imageId); } - bool hasPendingRequests() const { return !pendingRequests.empty(); } - void removePendingRequest(const std::string& imageId) { pendingRequests.erase(imageId); } - private: ImageManager& imageManager; - - // Pending requests are image requests that are waiting to be dispatched to the client. - std::set pendingRequests; }; } // namespace mbgl diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp index 20c0a3a7f3..16700d713f 100644 --- a/test/renderer/image_manager.test.cpp +++ b/test/renderer/image_manager.test.cpp @@ -187,30 +187,6 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) { EXPECT_EQ(observer.count, 1); ASSERT_TRUE(notified); - // Repeated request of the same image shall not result another - // `ImageManagerObserver.onStyleImageMissing()` call. - imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); - runLoop.runOnce(); - - EXPECT_EQ(observer.count, 1); - - // Request for updated dependencies must be dispatched to the - // observer. - dependencies.emplace("post", ImageType::Icon); - imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); - runLoop.runOnce(); - - EXPECT_EQ(observer.count, 2); - - // Another requestor shall not have pending requests for already obtained images. - StubImageRequestor anotherRequestor(imageManager); - imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID)); - ASSERT_FALSE(anotherRequestor.hasPendingRequests()); - - dependencies.emplace("unfamiliar", ImageType::Icon); - imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID)); - EXPECT_TRUE(anotherRequestor.hasPendingRequests()); - EXPECT_TRUE(anotherRequestor.hasPendingRequest("unfamiliar")); } TEST(ImageManager, OnStyleImageMissingAfterSpriteLoaded) { -- cgit v1.2.1 From 646d4e3996513ed3e9247e958d39ce9e9b506652 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 24 Oct 2019 13:18:17 +0300 Subject: [core] Fixed formatting --- src/mbgl/renderer/image_manager.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index d001084f92..cc3e29cc79 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -180,27 +180,24 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR if (!missingImages.empty()) { ImageRequestor* requestorPtr = &requestor; - auto emplaced = missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair { pair, {} }); + auto emplaced = missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair{pair, {}}); assert(emplaced.second); for (const auto& missingImage : missingImages) { assert(observer != nullptr); requestedImages[missingImage].emplace(&requestor); - auto callback = std::make_unique( - *Scheduler::GetCurrent(), - [this, requestorPtr, missingImage] { + auto callback = + std::make_unique(*Scheduler::GetCurrent(), [this, requestorPtr, missingImage] { auto requestorIt = missingImageRequestors.find(requestorPtr); if (requestorIt != missingImageRequestors.end()) { assert(requestorIt->second.callbacks.find(missingImage) != requestorIt->second.callbacks.end()); requestorIt->second.callbacks.erase(missingImage); } - }); + }); auto actorRef = callback->self(); emplaced.first->second.callbacks.emplace(missingImage, std::move(callback)); - observer->onStyleImageMissing(missingImage, [actorRef] { - actorRef.invoke(&Callback::operator()); - }); + observer->onStyleImageMissing(missingImage, [actorRef] { actorRef.invoke(&Callback::operator()); }); } } else { // Associate requestor with an image that was provided by the client. -- cgit v1.2.1 From 128da903c19c860e89be36bf67bd02cfa408a525 Mon Sep 17 00:00:00 2001 From: zmiao Date: Fri, 25 Oct 2019 18:22:32 +0300 Subject: Config CircleCI to save render test output when failing (#15863) * [render-test] Save index.html * Add extra folder --- circle.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 11954ccf6d..103ea8c685 100644 --- a/circle.yml +++ b/circle.yml @@ -267,7 +267,9 @@ commands: when: on_fail command: | mkdir -p /tmp/tests/render - if [ -f mapbox-gl-js/test/integration/index.html ]; then cp mapbox-gl-js/test/integration/index.html /tmp/tests/render; fi + mkdir -p /tmp/tests/probe + if [ -f index.html ]; then cp index.html /tmp/tests/render; fi + if [ -f render-test/index.html ]; then cp render-test/index.html /tmp/tests/probe; fi mkdir -p /tmp/tests/coredumps if ls core* 1> /dev/null 2>&1; then cp core* /tmp/tests/coredumps; fi - store_artifacts: -- cgit v1.2.1 From 6428d12a8d3de572973202016b9ee19df4b288ed Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Sat, 26 Oct 2019 12:47:30 +0300 Subject: [core] Bump mapbox-gl-js version --- mapbox-gl-js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index e18977bb07..6453c38a51 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit e18977bb0771b981c47404f4b8711c456a487d5f +Subproject commit 6453c38a5118e52e7cc7fb9b6e23d28e5bf5268b -- cgit v1.2.1 From aa36dc87fb5583425ab29b4a15407186c31c492f Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Thu, 24 Oct 2019 17:05:01 +0300 Subject: Revert "[core] Revert coalescing requests to the client for the same missing image" This reverts commit 22132683797b5ea5cbe8622f77c01b399ad9c71e. --- src/mbgl/renderer/image_manager.cpp | 70 +++++++++++++++++++++++------------- src/mbgl/renderer/image_manager.hpp | 17 +++++---- test/renderer/image_manager.test.cpp | 24 +++++++++++++ 3 files changed, 80 insertions(+), 31 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index cc3e29cc79..7b51fb9a2e 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -138,8 +138,9 @@ void ImageManager::removeRequestor(ImageRequestor& requestor) { void ImageManager::notifyIfMissingImageAdded() { for (auto it = missingImageRequestors.begin(); it != missingImageRequestors.end();) { - if (it->second.callbacks.empty()) { - notify(*it->first, it->second.pair); + ImageRequestor& requestor = *it->first; + if (!requestor.hasPendingRequests()) { + notify(requestor, it->second); it = missingImageRequestors.erase(it); } else { ++it; @@ -169,35 +170,56 @@ void ImageManager::reduceMemoryUseIfCacheSizeExceedsLimit() { } void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageRequestPair& pair) { - std::vector missingImages; - missingImages.reserve(pair.first.size()); + ImageDependencies missingDependencies; + for (const auto& dependency : pair.first) { if (images.find(dependency.first) == images.end()) { - missingImages.push_back(dependency.first); + missingDependencies.emplace(dependency); } } - if (!missingImages.empty()) { + if (!missingDependencies.empty()) { ImageRequestor* requestorPtr = &requestor; + assert(!missingImageRequestors.count(requestorPtr)); + missingImageRequestors.emplace(requestorPtr, pair); - auto emplaced = missingImageRequestors.emplace(requestorPtr, MissingImageRequestPair{pair, {}}); - assert(emplaced.second); - - for (const auto& missingImage : missingImages) { + for (const auto& dependency : missingDependencies) { + const std::string& missingImage = dependency.first; assert(observer != nullptr); - requestedImages[missingImage].emplace(&requestor); - auto callback = - std::make_unique(*Scheduler::GetCurrent(), [this, requestorPtr, missingImage] { - auto requestorIt = missingImageRequestors.find(requestorPtr); - if (requestorIt != missingImageRequestors.end()) { - assert(requestorIt->second.callbacks.find(missingImage) != requestorIt->second.callbacks.end()); - requestorIt->second.callbacks.erase(missingImage); - } - }); - - auto actorRef = callback->self(); - emplaced.first->second.callbacks.emplace(missingImage, std::move(callback)); - observer->onStyleImageMissing(missingImage, [actorRef] { actorRef.invoke(&Callback::operator()); }); + + auto existingRequestorsIt = requestedImages.find(missingImage); + if (existingRequestorsIt != requestedImages.end()) { // Already asked client about this image. + std::set& existingRequestors = existingRequestorsIt->second; + if (!existingRequestors.empty() && + (*existingRequestors.begin()) + ->hasPendingRequest(missingImage)) { // Still waiting for the client response for this image. + requestorPtr->addPendingRequest(missingImage); + existingRequestors.emplace(requestorPtr); + continue; + } + // Unlike icons, pattern changes are not caught + // with style-diff meaning that the existing request + // could be from the previous style and we cannot + // coalesce requests for them. + if (dependency.second != ImageType::Pattern) { + continue; + } + } + requestedImages[missingImage].emplace(requestorPtr); + requestor.addPendingRequest(missingImage); + + auto removePendingRequests = [this, missingImage] { + auto existingRequest = requestedImages.find(missingImage); + if (existingRequest == requestedImages.end()) { + return; + } + + for (auto* req : existingRequest->second) { + req->removePendingRequest(missingImage); + } + }; + observer->onStyleImageMissing(missingImage, + Scheduler::GetCurrent()->bindOnce(std::move(removePendingRequests))); } } else { // Associate requestor with an image that was provided by the client. @@ -227,7 +249,7 @@ void ImageManager::notify(ImageRequestor& requestor, const ImageRequestPair& pai } } - requestor.onImagesAvailable(iconMap, patternMap, std::move(versionMap), pair.second); + requestor.onImagesAvailable(std::move(iconMap), std::move(patternMap), std::move(versionMap), pair.second); } void ImageManager::dumpDebugLogs() const { diff --git a/src/mbgl/renderer/image_manager.hpp b/src/mbgl/renderer/image_manager.hpp index 9097418681..5ed6e237f0 100644 --- a/src/mbgl/renderer/image_manager.hpp +++ b/src/mbgl/renderer/image_manager.hpp @@ -58,13 +58,7 @@ private: bool loaded = false; std::map requestors; - using Callback = std::function; - using ActorCallback = Actor; - struct MissingImageRequestPair { - ImageRequestPair pair; - std::map> callbacks; - }; - std::map missingImageRequestors; + std::map missingImageRequestors; std::map> requestedImages; std::size_t requestedImagesCacheSize = 0ul; ImageMap images; @@ -77,8 +71,17 @@ public: explicit ImageRequestor(ImageManager&); virtual ~ImageRequestor(); virtual void onImagesAvailable(ImageMap icons, ImageMap patterns, ImageVersionMap versionMap, uint64_t imageCorrelationID) = 0; + + void addPendingRequest(const std::string& imageId) { pendingRequests.insert(imageId); } + bool hasPendingRequest(const std::string& imageId) const { return pendingRequests.count(imageId); } + bool hasPendingRequests() const { return !pendingRequests.empty(); } + void removePendingRequest(const std::string& imageId) { pendingRequests.erase(imageId); } + private: ImageManager& imageManager; + + // Pending requests are image requests that are waiting to be dispatched to the client. + std::set pendingRequests; }; } // namespace mbgl diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp index 16700d713f..20c0a3a7f3 100644 --- a/test/renderer/image_manager.test.cpp +++ b/test/renderer/image_manager.test.cpp @@ -187,6 +187,30 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) { EXPECT_EQ(observer.count, 1); ASSERT_TRUE(notified); + // Repeated request of the same image shall not result another + // `ImageManagerObserver.onStyleImageMissing()` call. + imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); + runLoop.runOnce(); + + EXPECT_EQ(observer.count, 1); + + // Request for updated dependencies must be dispatched to the + // observer. + dependencies.emplace("post", ImageType::Icon); + imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); + runLoop.runOnce(); + + EXPECT_EQ(observer.count, 2); + + // Another requestor shall not have pending requests for already obtained images. + StubImageRequestor anotherRequestor(imageManager); + imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID)); + ASSERT_FALSE(anotherRequestor.hasPendingRequests()); + + dependencies.emplace("unfamiliar", ImageType::Icon); + imageManager.getImages(anotherRequestor, std::make_pair(dependencies, ++imageCorrelationID)); + EXPECT_TRUE(anotherRequestor.hasPendingRequests()); + EXPECT_TRUE(anotherRequestor.hasPendingRequest("unfamiliar")); } TEST(ImageManager, OnStyleImageMissingAfterSpriteLoaded) { -- cgit v1.2.1 From 2f00ba72946618b6baac03ae395645cbeb83fe00 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 25 Oct 2019 15:13:02 +0300 Subject: [core] Do not make pending requests for already requested images. so that processing for the corresponding tile does not suspend and the rendering performance is not affected. --- src/mbgl/renderer/image_manager.cpp | 15 ++++++--------- test/renderer/image_manager.test.cpp | 12 +++--------- 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 7b51fb9a2e..108376d190 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -197,16 +197,13 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR existingRequestors.emplace(requestorPtr); continue; } - // Unlike icons, pattern changes are not caught - // with style-diff meaning that the existing request - // could be from the previous style and we cannot - // coalesce requests for them. - if (dependency.second != ImageType::Pattern) { - continue; - } + // The request for this image has been already delivered + // to the client, so we do not treat it as pending. + existingRequestors.emplace(requestorPtr); + } else { + requestedImages[missingImage].emplace(requestorPtr); + requestor.addPendingRequest(missingImage); } - requestedImages[missingImage].emplace(requestorPtr); - requestor.addPendingRequest(missingImage); auto removePendingRequests = [this, missingImage] { auto existingRequest = requestedImages.find(missingImage); diff --git a/test/renderer/image_manager.test.cpp b/test/renderer/image_manager.test.cpp index 20c0a3a7f3..d1d0a83c44 100644 --- a/test/renderer/image_manager.test.cpp +++ b/test/renderer/image_manager.test.cpp @@ -187,20 +187,14 @@ TEST(ImageManager, OnStyleImageMissingBeforeSpriteLoaded) { EXPECT_EQ(observer.count, 1); ASSERT_TRUE(notified); - // Repeated request of the same image shall not result another - // `ImageManagerObserver.onStyleImageMissing()` call. - imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); - runLoop.runOnce(); - - EXPECT_EQ(observer.count, 1); - // Request for updated dependencies must be dispatched to the // observer. dependencies.emplace("post", ImageType::Icon); imageManager.getImages(requestor, std::make_pair(dependencies, ++imageCorrelationID)); - runLoop.runOnce(); + ASSERT_TRUE(requestor.hasPendingRequests()); - EXPECT_EQ(observer.count, 2); + runLoop.runOnce(); + ASSERT_FALSE(requestor.hasPendingRequests()); // Another requestor shall not have pending requests for already obtained images. StubImageRequestor anotherRequestor(imageManager); -- cgit v1.2.1 From f1a28377b5560fe3de48fcb51d5020c65eaf0964 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Sat, 26 Oct 2019 12:24:03 +0300 Subject: [core] Add Map.NoHangOnMissingImage unit test --- test/map/map.test.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 3f3145059a..6f4b14a681 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -1009,3 +1009,54 @@ TEST(Map, UniversalStyleGetter) { ASSERT_TRUE(lineCap.getValue().getString()); EXPECT_EQ(std::string("butt"), *lineCap.getValue().getString()); } + +TEST(Map, NoHangOnMissingImage) { + MapTest<> test; + + test.fileSource->tileResponse = [&](const Resource&) { + Response result; + result.data = std::make_shared(util::read_file("test/fixtures/map/issue12432/0-0-0.mvt")); + return result; + }; + + test.fileSource->spriteImageResponse = [&](const Resource&) { + Response result; + result.data = std::make_shared(util::read_file("test/fixtures/resources/sprite.png")); + return result; + }; + + test.fileSource->spriteJSONResponse = [&](const Resource&) { + Response result; + result.data = std::make_shared(util::read_file("test/fixtures/resources/sprite.json")); + return result; + }; + + const std::string style{R"STYLE({ + "version": 8, + "sprite": "http://example.com/sprites/sprite", + "sources": { + "mapbox": { + "type": "vector", + "tiles": ["http://example.com/{z}-{x}-{y}.vector.pbf"] + } + }, + "layers": [{ + "id": "background", + "type": "background", + "paint": {"background-color": "white"} + },{ + "id": "water", + "type": "fill", + "source": "mapbox", + "source-layer": "water", + "paint": {"fill-pattern": "missing"} + }] + })STYLE"}; + test.map.getStyle().loadJSON(style); + test.frontend.render(test.map); + + test.map.getStyle().loadJSON(style); + test.map.jumpTo(test.map.getStyle().getDefaultCamera()); + // The test passes if the following call does not hang. + test.frontend.render(test.map); +} \ No newline at end of file -- cgit v1.2.1 From bdbb1366123b4e2cbdba93dcbb6707924229cd83 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Mon, 28 Oct 2019 12:23:50 +0200 Subject: [ios][android][core] Added change log entries and more code comments --- platform/android/CHANGELOG.md | 3 +++ platform/ios/CHANGELOG.md | 3 ++- src/mbgl/renderer/image_manager.cpp | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index cc572194e8..7722736100 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,6 +4,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master +### Bug fixes + - Fixed the rendering bug caused by redundant pending requests for already requested images [#15864](https://github.com/mapbox/mapbox-gl-native/pull/15864) + ### Performance improvements - Enable incremental vacuum for the offline database in order to make data removal requests faster and to avoid the excessive disk space usage (creating a backup file on VACUUM call) [#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 0c776b0944..98761737f7 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -6,7 +6,8 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Other changes -* Coalesce requests to the client for the same missing image ([#15778](https://github.com/mapbox/mapbox-gl-native/pull/15778)) +### Bug fixes +* Fixed the rendering bug caused by redundant pending requests for already requested images [#15864](https://github.com/mapbox/mapbox-gl-native/pull/15864) * Enable incremental vacuum for the offline database in order to make data removal requests faster and to avoid the excessive disk space usage (creating a backup file on VACUUM call). ([#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837)) ## 5.5.0 diff --git a/src/mbgl/renderer/image_manager.cpp b/src/mbgl/renderer/image_manager.cpp index 108376d190..2ea753d8aa 100644 --- a/src/mbgl/renderer/image_manager.cpp +++ b/src/mbgl/renderer/image_manager.cpp @@ -190,6 +190,7 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR auto existingRequestorsIt = requestedImages.find(missingImage); if (existingRequestorsIt != requestedImages.end()) { // Already asked client about this image. std::set& existingRequestors = existingRequestorsIt->second; + // existingRequestors is empty if all the previous requestors are deleted. if (!existingRequestors.empty() && (*existingRequestors.begin()) ->hasPendingRequest(missingImage)) { // Still waiting for the client response for this image. @@ -200,6 +201,8 @@ void ImageManager::checkMissingAndNotify(ImageRequestor& requestor, const ImageR // The request for this image has been already delivered // to the client, so we do not treat it as pending. existingRequestors.emplace(requestorPtr); + // TODO: we could `continue;` here, but we need to call `observer->onStyleImageMissing`, + // so that rendering is re-launched from the handler at Map::Impl. } else { requestedImages[missingImage].emplace(requestorPtr); requestor.addPendingRequest(missingImage); -- cgit v1.2.1 From 7c9c71fba1233a6474bd4a8885e9e5d7588fd890 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Thu, 3 Oct 2019 16:10:33 +0300 Subject: [build] update mapbox-base --- vendor/mapbox-base | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/mapbox-base b/vendor/mapbox-base index a951030b70..52e06d824b 160000 --- a/vendor/mapbox-base +++ b/vendor/mapbox-base @@ -1 +1 @@ -Subproject commit a951030b7076c74de3faed932e4f7b3700aa0947 +Subproject commit 52e06d824be1986643f8c058dea78223e1e5267e -- cgit v1.2.1 From 360b8b42471d7196511ab11edb4f9f277329af13 Mon Sep 17 00:00:00 2001 From: Juha Alanen Date: Thu, 3 Oct 2019 15:57:05 +0300 Subject: [core,android,darwin,qt] Add fields related to feature-state Move the fields from geometry.hpp/feature.hpp as they are not part of the GeoJSON specification. --- include/mbgl/util/feature.hpp | 16 +++++++++++++++- platform/android/src/geojson/feature.cpp | 25 +++++++++++++++++-------- platform/android/src/geojson/feature.hpp | 3 ++- platform/darwin/src/MGLComputedShapeSource.mm | 4 ++-- platform/darwin/src/MGLFeature.mm | 18 +++++++++++++----- platform/darwin/src/MGLFeature_Private.h | 15 +++++++++++---- platform/darwin/src/MGLShapeSource.mm | 8 ++++---- platform/qt/src/qt_geojson.cpp | 2 +- platform/qt/src/qt_geojson.hpp | 2 +- render-test/parser.cpp | 20 +++++++++++++------- 10 files changed, 79 insertions(+), 34 deletions(-) diff --git a/include/mbgl/util/feature.hpp b/include/mbgl/util/feature.hpp index 6080976945..5d8fe89e36 100644 --- a/include/mbgl/util/feature.hpp +++ b/include/mbgl/util/feature.hpp @@ -11,11 +11,25 @@ using Value = mapbox::base::Value; using NullValue = mapbox::base::NullValue; using PropertyMap = mapbox::base::ValueObject; using FeatureIdentifier = mapbox::feature::identifier; -using Feature = mapbox::feature::feature; +using GeoJSONFeature = mapbox::feature::feature; using FeatureState = mapbox::base::ValueObject; using FeatureStates = std::unordered_map; // using LayerFeatureStates = std::unordered_map; // +class Feature : public GeoJSONFeature { +public: + std::string source; + std::string sourceLayer; + PropertyMap state; + + using GeometryType = mapbox::geometry::geometry; + + Feature() = default; + Feature(const GeoJSONFeature& f) : GeoJSONFeature(f) {} + Feature(const GeometryType& geom_) : GeoJSONFeature(geom_) {} + Feature(GeometryType&& geom_) : GeoJSONFeature(std::move(geom_)) {} +}; + template optional numericValue(const Value& value) { return value.match( diff --git a/platform/android/src/geojson/feature.cpp b/platform/android/src/geojson/feature.cpp index 8d30404a50..afbf1ee11e 100644 --- a/platform/android/src/geojson/feature.cpp +++ b/platform/android/src/geojson/feature.cpp @@ -10,7 +10,7 @@ namespace geojson { using namespace gson; -mbgl::Feature Feature::convert(jni::JNIEnv& env, const jni::Object& jFeature) { +mbgl::GeoJSONFeature Feature::convert(jni::JNIEnv& env, const jni::Object& jFeature) { static auto& javaClass = jni::Class::Singleton(env); static auto id = javaClass.GetMethod(env, "id"); static auto geometry = javaClass.GetMethod ()>(env, "geometry"); @@ -20,11 +20,9 @@ mbgl::Feature Feature::convert(jni::JNIEnv& env, const jni::Object& jFe using mbid = mapbox::feature::identifier; - return mbgl::Feature { - Geometry::convert(env, jFeature.Call(env, geometry)), - JsonObject::convert(env, jFeature.Call(env, properties)), - jId ? mbid { jni::Make(env, jId) } : mbid { mapbox::feature::null_value } - }; + return mbgl::GeoJSONFeature{Geometry::convert(env, jFeature.Call(env, geometry)), + JsonObject::convert(env, jFeature.Call(env, properties)), + jId ? mbid{jni::Make(env, jId)} : mbid{mapbox::feature::null_value}}; } /** @@ -50,7 +48,7 @@ public: } }; -jni::Local> convertFeature(jni::JNIEnv& env, const mbgl::Feature& value) { +jni::Local> convertFeature(jni::JNIEnv& env, const mbgl::GeoJSONFeature& value) { static auto& javaClass = jni::Class::Singleton(env); static auto method = javaClass.GetStaticMethod (jni::Object, jni::Object, jni::String)>(env, "fromGeometry"); @@ -63,7 +61,18 @@ jni::Local> convertFeature(jni::JNIEnv& env, const mbgl::Fe jni::Local>> Feature::convert(jni::JNIEnv& env, const std::vector& value) { auto features = jni::Array>::New(env, value.size()); - for (size_t i = 0; i < value.size(); i = i + 1) { + for (size_t i = 0; i < value.size(); ++i) { + features.Set(env, i, convertFeature(env, static_cast(value.at(i)))); + } + + return features; +} + +jni::Local>> Feature::convert(jni::JNIEnv& env, + const std::vector& value) { + auto features = jni::Array>::New(env, value.size()); + + for (size_t i = 0; i < value.size(); ++i) { features.Set(env, i, convertFeature(env, value.at(i))); } diff --git a/platform/android/src/geojson/feature.hpp b/platform/android/src/geojson/feature.hpp index fdf5d977ba..aee45262e3 100644 --- a/platform/android/src/geojson/feature.hpp +++ b/platform/android/src/geojson/feature.hpp @@ -12,8 +12,9 @@ class Feature { public: static constexpr auto Name() { return "com/mapbox/geojson/Feature"; }; - static mbgl::Feature convert(jni::JNIEnv&, const jni::Object&); + static mbgl::GeoJSONFeature convert(jni::JNIEnv&, const jni::Object&); static jni::Local>> convert(jni::JNIEnv&, const std::vector&); + static jni::Local>> convert(jni::JNIEnv&, const std::vector&); static void registerNative(jni::JNIEnv&); }; diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm index a04181af2f..ceb83b3740 100644 --- a/platform/darwin/src/MGLComputedShapeSource.mm +++ b/platform/darwin/src/MGLComputedShapeSource.mm @@ -140,7 +140,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi @"This will be logged only once."); }); } - mbgl::Feature geoJsonObject = [feature geoJSONObject].get(); + mbgl::GeoJSONFeature geoJsonObject = [feature geoJSONObject].get(); featureCollection.push_back(geoJsonObject); } const auto geojson = mbgl::GeoJSON{featureCollection}; @@ -204,7 +204,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi mbgl::FeatureCollection featureCollection; featureCollection.reserve(features.count); for (MGLShape * feature in features) { - mbgl::Feature geoJsonObject = [feature geoJSONObject].get(); + mbgl::GeoJSONFeature geoJsonObject = [feature geoJSONObject].get(); featureCollection.push_back(geoJsonObject); if ([feature isMemberOfClass:[MGLShapeCollection class]]) { static dispatch_once_t onceToken; diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm index fbf262af29..df6b1bffea 100644 --- a/platform/darwin/src/MGLFeature.mm +++ b/platform/darwin/src/MGLFeature.mm @@ -336,8 +336,8 @@ MGL_DEFINE_FEATURE_ATTRIBUTES_GETTER(); featureCollection.reserve(self.shapes.count); for (MGLShape *feature in self.shapes) { auto geoJSONObject = feature.geoJSONObject; - MGLAssert(geoJSONObject.is(), @"Feature collection must only contain features."); - featureCollection.push_back(geoJSONObject.get()); + MGLAssert(geoJSONObject.is(), @"Feature collection must only contain features."); + featureCollection.push_back(geoJSONObject.get()); } return featureCollection; } @@ -470,7 +470,7 @@ public: return shape; } - MGLShape * operator()(const mbgl::Feature &feature) const { + MGLShape * operator()(const mbgl::GeoJSONFeature &feature) const { MGLShape *shape = (MGLShape *)MGLFeatureFromMBGLFeature(feature); return shape; } @@ -485,6 +485,14 @@ public: }; NSArray *> *MGLFeaturesFromMBGLFeatures(const std::vector &features) { + NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()]; + for (const auto &feature : features) { + [shapes addObject:MGLFeatureFromMBGLFeature(static_cast(feature))]; + } + return shapes; +} + +NSArray *> *MGLFeaturesFromMBGLFeatures(const std::vector &features) { NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()]; for (const auto &feature : features) { [shapes addObject:MGLFeatureFromMBGLFeature(feature)]; @@ -492,7 +500,7 @@ NSArray *> *MGLFeaturesFromMBGLFeatures(const std::vector< return shapes; } -id MGLFeatureFromMBGLFeature(const mbgl::Feature &feature) { +id MGLFeatureFromMBGLFeature(const mbgl::GeoJSONFeature &feature) { NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithCapacity:feature.properties.size()]; for (auto &pair : feature.properties) { auto &value = pair.second; @@ -515,7 +523,7 @@ MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson) { return shape; } -mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *attributes) +mbgl::GeoJSONFeature mbglFeature(mbgl::GeoJSONFeature feature, id identifier, NSDictionary *attributes) { if (identifier) { NSExpression *identifierExpression = [NSExpression expressionForConstantValue:identifier]; diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h index 9b0e16f4b9..599633dd31 100644 --- a/platform/darwin/src/MGLFeature_Private.h +++ b/platform/darwin/src/MGLFeature_Private.h @@ -16,10 +16,17 @@ MGL_EXPORT NSArray *> *MGLFeaturesFromMBGLFeatures(const std::vector &features); /** - Returns an `MGLFeature` object converted from the given mbgl::Feature + Returns an array of `MGLFeature` objects converted from the given vector of + vector tile features. + */ +MGL_EXPORT +NSArray *> *MGLFeaturesFromMBGLFeatures(const std::vector &features); + +/** + Returns an `MGLFeature` object converted from the given mbgl::GeoJSONFeature */ MGL_EXPORT -id MGLFeatureFromMBGLFeature(const mbgl::Feature &feature); +id MGLFeatureFromMBGLFeature(const mbgl::GeoJSONFeature &feature); /** Returns an `MGLShape` representing the given geojson. The shape can be @@ -28,11 +35,11 @@ id MGLFeatureFromMBGLFeature(const mbgl::Feature &feature); MGLShape* MGLShapeFromGeoJSON(const mapbox::geojson::geojson &geojson); /** - Takes an `mbgl::Feature` object, an identifer, and attributes dictionary and + Takes an `mbgl::GeoJSONFeature` object, an identifer, and attributes dictionary and returns the feature object with converted `mbgl::FeatureIdentifier` and `mbgl::PropertyMap` properties. */ -mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary * attributes); +mbgl::GeoJSONFeature mbglFeature(mbgl::GeoJSONFeature feature, id identifier, NSDictionary * attributes); /** Returns an `NSDictionary` representation of an `MGLFeature`. diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm index 3820fe9d60..a4a100aaa2 100644 --- a/platform/darwin/src/MGLShapeSource.mm +++ b/platform/darwin/src/MGLShapeSource.mm @@ -262,12 +262,12 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary()) { + if (!geoJSON.is()) { MGLAssert(0, @"cluster geoJSON object is not a feature."); return extensionValue; } - auto clusterFeature = geoJSON.get(); + auto clusterFeature = geoJSON.get(); extensionValue = self.mapView.renderer->queryFeatureExtensions(self.rawSource->getID(), clusterFeature, @@ -293,7 +293,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary leaves = featureExtension->get(); + std::vector leaves = featureExtension->get(); return MGLFeaturesFromMBGLFeatures(leaves); } @@ -308,7 +308,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary leaves = featureExtension->get(); + std::vector leaves = featureExtension->get(); return MGLFeaturesFromMBGLFeatures(leaves); } diff --git a/platform/qt/src/qt_geojson.cpp b/platform/qt/src/qt_geojson.cpp index 48d78abfe0..3b775685b1 100644 --- a/platform/qt/src/qt_geojson.cpp +++ b/platform/qt/src/qt_geojson.cpp @@ -121,7 +121,7 @@ mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id) { } } -mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature) { +mbgl::GeoJSONFeature asMapboxGLFeature(const QMapbox::Feature &feature) { mbgl::PropertyMap properties; properties.reserve(feature.properties.size()); for (auto it = feature.properties.constBegin(); it != feature.properties.constEnd(); ++it) { diff --git a/platform/qt/src/qt_geojson.hpp b/platform/qt/src/qt_geojson.hpp index a9c10272ab..a7db3ba644 100644 --- a/platform/qt/src/qt_geojson.hpp +++ b/platform/qt/src/qt_geojson.hpp @@ -22,6 +22,6 @@ mbgl::Polygon asMapboxGLPolygon(const QMapbox::CoordinatesCollection &po mbgl::MultiPolygon asMapboxGLMultiPolygon(const QMapbox::CoordinatesCollections &multiPolygon); mbgl::Value asMapboxGLPropertyValue(const QVariant &value); mbgl::FeatureIdentifier asMapboxGLFeatureIdentifier(const QVariant &id); -mbgl::Feature asMapboxGLFeature(const QMapbox::Feature &feature); +mbgl::GeoJSONFeature asMapboxGLFeature(const QMapbox::Feature &feature); } // namespace QMapbox diff --git a/render-test/parser.cpp b/render-test/parser.cpp index f410ffa860..11a42f3202 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -252,14 +252,20 @@ std::string toJSON(const std::vector& features, unsigned indent, } writer.SetIndent(' ', indent); writer.StartArray(); - for (size_t i = 0; i < features.size(); ++i) { - auto result = mapbox::geojson::convert(features[i], allocator); - - result.AddMember("source", features[i].source, allocator); - if (!features[i].sourceLayer.empty()) { - result.AddMember("sourceLayer", features[i].sourceLayer, allocator); + for (const auto& feature : features) { + mbgl::JSValue result(rapidjson::kObjectType); + result.AddMember("type", "Feature", allocator); + if (!feature.id.is()) { + result.AddMember( + "id", mapbox::geojson::identifier::visit(feature.id, mapbox::geojson::to_value{allocator}), allocator); + } + result.AddMember("geometry", mapbox::geojson::convert(feature.geometry, allocator), allocator); + result.AddMember("properties", mapbox::geojson::to_value{allocator}(feature.properties), allocator); + result.AddMember("source", feature.source, allocator); + if (!feature.sourceLayer.empty()) { + result.AddMember("sourceLayer", feature.sourceLayer, allocator); } - result.AddMember("state", mapbox::geojson::to_value{allocator}(features[i].state), allocator); + result.AddMember("state", mapbox::geojson::to_value{allocator}(feature.state), allocator); result.Accept(writer); } writer.EndArray(); -- cgit v1.2.1 From 84f2ff1084ccaec68c7a26243367ae657f6ebe60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 25 Oct 2019 11:57:09 +0200 Subject: [core] use individual textures for line dash patterns This moves the LineAtlas from a shared texture that contained SDF dash patterns to use individual textures. Previously, the texture space was limited to a texture of 512 pixels height. Dash patterns were never removed (and are still never removed as of this patch), which means that this texture could fill up for styles that use a lot of different dash patterns. In particular, dash patterns for lines with a round line cap take up 15 pixels of texture height, limiting the amount of unique dash patterns to 34. While this was probably enough for rendering a single style, we quickly exhausted this number when reusing the Map object to render different styles. Instead of a global shared texture, we're now creating individual textures for every dash pattern. These textures are still cached so that we don't need to re-upload the texture on every frame. --- src/mbgl/geometry/line_atlas.cpp | 128 +++++++++++++++---------- src/mbgl/geometry/line_atlas.hpp | 50 ++++++---- src/mbgl/renderer/layers/render_line_layer.cpp | 41 ++++---- src/mbgl/renderer/render_orchestrator.cpp | 24 +++-- test/geometry/line_atlas.test.cpp | 4 +- 5 files changed, 143 insertions(+), 104 deletions(-) diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index 106a24d015..2e4de3edbe 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -1,50 +1,33 @@ #include #include +#include +#include #include #include -#include #include namespace mbgl { +namespace { -LineAtlas::LineAtlas(const Size size) - : image(size), - dirty(true) { -} - -LineAtlas::~LineAtlas() = default; - -LinePatternPos LineAtlas::getDashPosition(const std::vector& dasharray, - LinePatternCap patternCap) { - size_t key = patternCap == LinePatternCap::Round ? std::numeric_limits::min() - : std::numeric_limits::max(); +size_t getDashPatternHash(const std::vector& dasharray, const LinePatternCap patternCap) { + size_t key = + patternCap == LinePatternCap::Round ? std::numeric_limits::min() : std::numeric_limits::max(); for (const float part : dasharray) { util::hash_combine(key, part); } - - // Note: We're not handling hash collisions here. - const auto it = positions.find(key); - if (it == positions.end()) { - auto inserted = positions.emplace(key, addDash(dasharray, patternCap)); - assert(inserted.second); - return inserted.first->second; - } else { - return it->second; - } + return key; } -LinePatternPos LineAtlas::addDash(const std::vector& dasharray, LinePatternCap patternCap) { +LinePatternPos addDashPattern(AlphaImage& image, + const int32_t yOffset, + const std::vector& dasharray, + const LinePatternCap patternCap) { const uint8_t n = patternCap == LinePatternCap::Round ? 7 : 0; - const uint8_t dashheight = 2 * n + 1; - const uint8_t offset = 128; + constexpr const uint8_t offset = 128; if (dasharray.size() < 2) { - return LinePatternPos(); - } - - if (nextRow + dashheight > image.size.height) { - Log::Warning(Event::OpenGL, "line atlas bitmap overflow"); + Log::Warning(Event::ParseStyle, "line dasharray requires at least two elements"); return LinePatternPos(); } @@ -60,7 +43,7 @@ LinePatternPos LineAtlas::addDash(const std::vector& dasharray, LinePatte bool oddLength = dasharray.size() % 2 == 1; for (int y = -n; y <= n; y++) { - int row = nextRow + n + y; + int row = yOffset + n + y; int index = image.size.width * row; float left = 0; @@ -72,7 +55,6 @@ LinePatternPos LineAtlas::addDash(const std::vector& dasharray, LinePatte } for (uint32_t x = 0; x < image.size.width; x++) { - while (right < x / stretch) { left = right; if (partIndex >= dasharray.size()) { @@ -111,37 +93,79 @@ LinePatternPos LineAtlas::addDash(const std::vector& dasharray, LinePatte } LinePatternPos position; - position.y = (0.5 + nextRow + n) / image.size.height; - position.height = (2.0 * n) / image.size.height; + position.y = (0.5 + yOffset + n) / image.size.height; + position.height = (2.0 * n + 1) / image.size.height; position.width = length; - nextRow += dashheight; - - dirty = true; - return position; } -Size LineAtlas::getSize() const { - return image.size; +} // namespace + +DashPatternTexture::DashPatternTexture(const std::vector& from_, + const std::vector& to_, + const LinePatternCap cap) { + const bool patternsIdentical = from_ == to_; + const int32_t patternHeight = cap == LinePatternCap::Round ? 15 : 1; + + AlphaImage image({256, static_cast((patternsIdentical ? 1 : 2) * patternHeight)}); + + from = addDashPattern(image, 0, from_, cap); + to = patternsIdentical ? from : addDashPattern(image, patternHeight, to_, cap); + + texture = std::move(image); } -void LineAtlas::upload(gfx::UploadPass& uploadPass) { - if (!texture) { - texture = uploadPass.createTexture(image); - } else if (dirty) { - uploadPass.updateTexture(*texture, image); +void DashPatternTexture::upload(gfx::UploadPass& uploadPass) { + if (texture.is()) { + texture = uploadPass.createTexture(texture.get()); } +} + +gfx::TextureBinding DashPatternTexture::textureBinding() const { + // The texture needs to have been uploaded already. + assert(texture.is()); + return {texture.get().getResource(), + gfx::TextureFilterType::Linear, + gfx::TextureMipMapType::No, + gfx::TextureWrapType::Repeat, + gfx::TextureWrapType::Clamp}; +} - dirty = false; +Size DashPatternTexture::getSize() const { + return texture.match([](const auto& obj) { return obj.size; }); } -gfx::TextureBinding LineAtlas::textureBinding() { - assert(texture); - // All _changes_ to the texture should've been made and uploaded already. - assert(!dirty); - return { texture->getResource(), gfx::TextureFilterType::Linear, gfx::TextureMipMapType::No, - gfx::TextureWrapType::Repeat, gfx::TextureWrapType::Clamp }; +LineAtlas::LineAtlas() = default; + +LineAtlas::~LineAtlas() = default; + +DashPatternTexture& LineAtlas::getDashPatternTexture(const std::vector& from, + const std::vector& to, + const LinePatternCap cap) { + const size_t hash = util::hash(getDashPatternHash(from, cap), getDashPatternHash(to, cap)); + + // Note: We're not handling hash collisions here. + const auto it = textures.find(hash); + if (it == textures.end()) { + auto inserted = textures.emplace( + std::piecewise_construct, std::forward_as_tuple(hash), std::forward_as_tuple(from, to, cap)); + assert(inserted.second); + needsUpload.emplace_back(hash); + return inserted.first->second; + } else { + return it->second; + } +} + +void LineAtlas::upload(gfx::UploadPass& uploadPass) { + for (const size_t hash : needsUpload) { + const auto it = textures.find(hash); + if (it != textures.end()) { + it->second.upload(uploadPass); + } + } + needsUpload.clear(); } } // namespace mbgl diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index b43583c9c8..853305d138 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -3,10 +3,11 @@ #include #include #include +#include -#include -#include +#include #include +#include namespace mbgl { @@ -26,29 +27,46 @@ enum class LinePatternCap : bool { Round = true, }; -class LineAtlas { +class DashPatternTexture { public: - LineAtlas(Size); - ~LineAtlas(); - - // Binds the atlas texture to the GPU, and uploads data if it is out of date. - gfx::TextureBinding textureBinding(); + DashPatternTexture(const std::vector& from, const std::vector& to, LinePatternCap); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; - // the texture is only bound when the data is out of date (=dirty). + // the texture is only bound when the data is uploaded for the first time. void upload(gfx::UploadPass&); - LinePatternPos getDashPosition(const std::vector&, LinePatternCap); - LinePatternPos addDash(const std::vector& dasharray, LinePatternCap); + // Binds the atlas texture to the GPU, and uploads data if it is out of date. + gfx::TextureBinding textureBinding() const; + // Returns the size of the texture image. Size getSize() const; + const LinePatternPos& getFrom() const { return from; } + const LinePatternPos& getTo() const { return to; } + private: - const AlphaImage image; - bool dirty; - optional texture; - uint32_t nextRow = 0; - std::unordered_map positions; + LinePatternPos from, to; + variant texture; +}; + +class LineAtlas { +public: + LineAtlas(); + ~LineAtlas(); + + // Obtains or creates a texture that has both line patterns in it + DashPatternTexture& getDashPatternTexture(const std::vector& from, + const std::vector& to, + LinePatternCap); + + // Uploads the textures to the GPU to be available when we need it. + void upload(gfx::UploadPass&); + +private: + std::map textures; + + // Stores a list of hashes of texture objcts that need uploading. + std::vector needsUpload; }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 36665c1db4..e5bbe74bf9 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -78,8 +78,8 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) { const LinePatternCap cap = bucket.layout.get() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; // Ensures that the dash data gets added to the atlas. - params.lineAtlas.getDashPosition(evaluated.get().from, cap); - params.lineAtlas.getDashPosition(evaluated.get().to, cap); + params.lineAtlas.getDashPatternTexture( + evaluated.get().from, evaluated.get().to, cap); } } @@ -146,27 +146,26 @@ void RenderLineLayer::render(PaintParameters& parameters) { }; if (!evaluated.get().from.empty()) { - const LinePatternCap cap = bucket.layout.get() == LineCapType::Round - ? LinePatternCap::Round : LinePatternCap::Square; - LinePatternPos posA = parameters.lineAtlas.getDashPosition(evaluated.get().from, cap); - LinePatternPos posB = parameters.lineAtlas.getDashPosition(evaluated.get().to, cap); + const LinePatternCap cap = + bucket.layout.get() == LineCapType::Round ? LinePatternCap::Round : LinePatternCap::Square; + const auto& dashPatternTexture = parameters.lineAtlas.getDashPatternTexture( + evaluated.get().from, evaluated.get().to, cap); draw(parameters.programs.getLineLayerPrograms().lineSDF, - LineSDFProgram::layoutUniformValues( - evaluated, - parameters.pixelRatio, - tile, - parameters.state, - parameters.pixelsToGLUnits, - posA, - posB, - crossfade, - parameters.lineAtlas.getSize().width), - {}, - {}, - LineSDFProgram::TextureBindings{ - parameters.lineAtlas.textureBinding(), - }); + LineSDFProgram::layoutUniformValues(evaluated, + parameters.pixelRatio, + tile, + parameters.state, + parameters.pixelsToGLUnits, + dashPatternTexture.getFrom(), + dashPatternTexture.getTo(), + crossfade, + dashPatternTexture.getSize().width), + {}, + {}, + LineSDFProgram::TextureBindings{ + dashPatternTexture.textureBinding(), + }); } else if (!unevaluated.get().isUndefined()) { const auto& linePatternValue = evaluated.get().constantOr(Faded>{ "", ""}); diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 50077784b5..e13a439ae4 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -103,19 +103,17 @@ public: } // namespace -RenderOrchestrator::RenderOrchestrator( - bool backgroundLayerAsColor_, - optional localFontFamily_) - : observer(&nullObserver()) - , glyphManager(std::make_unique(std::make_unique(std::move(localFontFamily_)))) - , imageManager(std::make_unique()) - , lineAtlas(std::make_unique(Size{ 256, 512 })) - , patternAtlas(std::make_unique()) - , imageImpls(makeMutable>>()) - , sourceImpls(makeMutable>>()) - , layerImpls(makeMutable>>()) - , renderLight(makeMutable()) - , backgroundLayerAsColor(backgroundLayerAsColor_) { +RenderOrchestrator::RenderOrchestrator(bool backgroundLayerAsColor_, optional localFontFamily_) + : observer(&nullObserver()), + glyphManager(std::make_unique(std::make_unique(std::move(localFontFamily_)))), + imageManager(std::make_unique()), + lineAtlas(std::make_unique()), + patternAtlas(std::make_unique()), + imageImpls(makeMutable>>()), + sourceImpls(makeMutable>>()), + layerImpls(makeMutable>>()), + renderLight(makeMutable()), + backgroundLayerAsColor(backgroundLayerAsColor_) { glyphManager->setObserver(this); imageManager->setObserver(this); } diff --git a/test/geometry/line_atlas.test.cpp b/test/geometry/line_atlas.test.cpp index 960e4ad7ad..1d817220e1 100644 --- a/test/geometry/line_atlas.test.cpp +++ b/test/geometry/line_atlas.test.cpp @@ -13,7 +13,7 @@ TEST(LineAtlas, Random) { std::normal_distribution lengthDistribution(3, 5); for (size_t it = 0; it < 100; it++) { - LineAtlas atlas{ Size{ 128, 1024 } }; + LineAtlas atlas; std::vector dasharray; dasharray.reserve(8); for (size_t j = 0; j < 100; j++) { @@ -25,7 +25,7 @@ TEST(LineAtlas, Random) { const LinePatternCap patternCap = capStyleDistribution(generator) > 0 ? LinePatternCap::Round : LinePatternCap::Square; - atlas.addDash(dasharray, patternCap); + atlas.getDashPatternTexture(dasharray, dasharray, patternCap); } } } -- cgit v1.2.1 From c8576e089f12438a2384a4fe822af650e94ace74 Mon Sep 17 00:00:00 2001 From: zmiao Date: Tue, 29 Oct 2019 20:59:29 +0200 Subject: [render-test] Add manifest parser for render-test-runner (#15861) * [render-test] Add manifest parser for render-test-runner * [render-test] Refactory manifest parser * [render-test] Parse full manifest file through CLI * [render-test] Add linux probe manifest --- circle.yml | 6 +- cmake/render-test.cmake | 2 + next/platform/linux/linux.cmake | 8 +- next/platform/macos/macos.cmake | 15 +- next/render-test/CMakeLists.txt | 2 + platform/android/src/test/render_test_runner.cpp | 2 +- render-test/android-manifest.json | 7 + render-test/android/render_test_setup.sh | 10 +- render-test/linux-manifest.json | 7 + render-test/linux-probe-manifest.json | 7 + render-test/mac-manifest.json | 7 + render-test/mac-probe-manifest.json | 7 + render-test/manifest_parser.cpp | 400 +++++++++++++++++++++++ render-test/manifest_parser.hpp | 55 ++++ render-test/parser.cpp | 398 +--------------------- render-test/parser.hpp | 20 +- render-test/render_test.cpp | 112 +++++-- render-test/runner.cpp | 20 +- render-test/runner.hpp | 11 +- 19 files changed, 635 insertions(+), 461 deletions(-) create mode 100644 render-test/android-manifest.json create mode 100644 render-test/linux-manifest.json create mode 100644 render-test/linux-probe-manifest.json create mode 100644 render-test/mac-manifest.json create mode 100644 render-test/mac-probe-manifest.json create mode 100644 render-test/manifest_parser.cpp create mode 100644 render-test/manifest_parser.hpp diff --git a/circle.yml b/circle.yml index 103ea8c685..ad4dc8bfd0 100644 --- a/circle.yml +++ b/circle.yml @@ -267,9 +267,9 @@ commands: when: on_fail command: | mkdir -p /tmp/tests/render - mkdir -p /tmp/tests/probe - if [ -f index.html ]; then cp index.html /tmp/tests/render; fi - if [ -f render-test/index.html ]; then cp render-test/index.html /tmp/tests/probe; fi + if [ -f render-test/tests_index.html ]; then cp render-test/tests_index.html /tmp/tests/render; fi + if [ -f render-test/render-tests_index.html ]; then cp render-test/render-tests_index.html /tmp/tests/render; fi + if [ -f render-test/query-tests_index.html ]; then cp render-test/query-tests_index.html /tmp/tests/render; fi mkdir -p /tmp/tests/coredumps if ls core* 1> /dev/null 2>&1; then cp core* /tmp/tests/coredumps; fi - store_artifacts: diff --git a/cmake/render-test.cmake b/cmake/render-test.cmake index 8726fb4650..ac17be559c 100644 --- a/cmake/render-test.cmake +++ b/cmake/render-test.cmake @@ -8,6 +8,8 @@ add_executable( render-test/filesystem.hpp render-test/filesystem.hpp render-test/include/mbgl/render_test.hpp + render-test/manifest_parser.cpp + render-test/manifest_parser.hpp render-test/metadata.hpp render-test/parser.cpp render-test/parser.hpp diff --git a/next/platform/linux/linux.cmake b/next/platform/linux/linux.cmake index 5bde30a61a..396b9a0ffd 100644 --- a/next/platform/linux/linux.cmake +++ b/next/platform/linux/linux.cmake @@ -144,14 +144,12 @@ add_test( render-tests --recycle-map --shuffle - --expectationsPath=render-test/expected/render-tests + --manifestPath=${MBGL_ROOT}/render-test/linux-manifest.json --seed=${MBGL_RENDER_TEST_SEED} - WORKING_DIRECTORY ${MBGL_ROOT} ) add_test( NAME mbgl-render-test-probes - COMMAND mbgl-render-test-runner tests --rootPath=${MBGL_ROOT}/render-test - WORKING_DIRECTORY ${MBGL_ROOT} + COMMAND mbgl-render-test-runner tests --manifestPath=${MBGL_ROOT}/render-test/linux-probe-manifest.json ) -add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests WORKING_DIRECTORY ${MBGL_ROOT}) +add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests --manifestPath=${MBGL_ROOT}/render-test/linux-manifest.json) diff --git a/next/platform/macos/macos.cmake b/next/platform/macos/macos.cmake index cfabcb1cfa..721d19e625 100644 --- a/next/platform/macos/macos.cmake +++ b/next/platform/macos/macos.cmake @@ -208,19 +208,10 @@ add_test( render-tests --recycle-map --shuffle - --expectationsPath=render-test/expected/render-tests + --manifestPath=${MBGL_ROOT}/render-test/mac-manifest.json --seed=${MBGL_RENDER_TEST_SEED} - WORKING_DIRECTORY ${MBGL_ROOT} ) -add_test( - NAME mbgl-render-test-probes - COMMAND - mbgl-render-test-runner - tests - --rootPath=${MBGL_ROOT}/render-test - --expectationsPath=tests/mac - WORKING_DIRECTORY ${MBGL_ROOT} -) +add_test(NAME mbgl-render-test-probes COMMAND mbgl-render-test-runner tests --manifestPath=${MBGL_ROOT}/render-test/mac-probe-manifest.json) -add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests WORKING_DIRECTORY ${MBGL_ROOT}) +add_test(NAME mbgl-query-test COMMAND mbgl-render-test-runner query-tests --manifestPath=${MBGL_ROOT}/render-test/mac-manifest.json) diff --git a/next/render-test/CMakeLists.txt b/next/render-test/CMakeLists.txt index 02ee6141cf..fa4bb0d615 100644 --- a/next/render-test/CMakeLists.txt +++ b/next/render-test/CMakeLists.txt @@ -8,6 +8,8 @@ add_library( ${MBGL_ROOT}/render-test/file_source.hpp ${MBGL_ROOT}/render-test/filesystem.hpp ${MBGL_ROOT}/render-test/include/mbgl/render_test.hpp + ${MBGL_ROOT}/render-test/manifest_parser.cpp + ${MBGL_ROOT}/render-test/manifest_parser.hpp ${MBGL_ROOT}/render-test/metadata.hpp ${MBGL_ROOT}/render-test/parser.cpp ${MBGL_ROOT}/render-test/parser.hpp diff --git a/platform/android/src/test/render_test_runner.cpp b/platform/android/src/test/render_test_runner.cpp index 3f85140128..d4554aa9de 100644 --- a/platform/android/src/test/render_test_runner.cpp +++ b/platform/android/src/test/render_test_runner.cpp @@ -46,7 +46,7 @@ void android_main(struct android_app* app) { JNIEnv* env; app->activity->vm->AttachCurrentThread(&env, NULL); - std::vector arguments = {"mbgl-render-test-runner", "-p", "/sdcard/render-test"}; + std::vector arguments = {"mbgl-render-test-runner", "-p", "/sdcard/render-test/android-manifest.json"}; std::vector argv; for (const auto& arg : arguments) { argv.push_back((char*)arg.data()); diff --git a/render-test/android-manifest.json b/render-test/android-manifest.json new file mode 100644 index 0000000000..56223d4753 --- /dev/null +++ b/render-test/android-manifest.json @@ -0,0 +1,7 @@ +{ + "base_test_path":"mapbox-gl-js/test/integration", + "expectation_paths":["render-test/expected/render-tests"], + "ignore_paths":["platform/node/test/ignores.json", "render-test/linux-ignores.json", "render-test/tests/should-fail.json"], + "vendor_path":"vendor", + "asset_path": "mapbox-gl-js/test/integration" +} \ No newline at end of file diff --git a/render-test/android/render_test_setup.sh b/render-test/android/render_test_setup.sh index e34d71df3b..1dea44399e 100755 --- a/render-test/android/render_test_setup.sh +++ b/render-test/android/render_test_setup.sh @@ -3,8 +3,8 @@ adb shell rm -rf /sdcard/render-test adb shell mkdir /sdcard/render-test adb shell mkdir /sdcard/render-test/vendor -adb shell mkdir /sdcard/render-test/expected adb shell mkdir /sdcard/render-test/ignores +adb shell mkdir /sdcard/render-test/render-test/tests # push test sources adb push ../../mapbox-gl-js/test/integration/render-tests /sdcard/render-test/mapbox-gl-js/test/integration/render-tests @@ -25,7 +25,7 @@ adb push sprites /sdcard/render-test/mapbox-gl-js/test/integration/sprites rm -rf sprites # push extra expectations -adb push ../../render-test/expected /sdcard/render-test/render-test/expected +adb push ../../render-test/expected/render-tests /sdcard/render-test/render-test/expected/render-tests # push default ignore lists adb shell mkdir /sdcard/render-test/platform @@ -33,6 +33,10 @@ adb shell mkdir /sdcard/render-test/platform/node adb shell mkdir /sdcard/render-test/platform/node/test adb push ../../platform/node/test/ignores.json /sdcard/render-test/platform/node/test adb shell mkdir /sdcard/render-test/render-test -adb push ../../render-test/linux-ignores.json /sdcard/render-test/render-test +adb push ../linux-ignores.json /sdcard/render-test/render-test +adb push ../tests/should-fail.json /sdcard/render-test/render-test/tests + +# push manifest +adb push ../android-manifest.json /sdcard/render-test adb shell ls /sdcard/render-test/ \ No newline at end of file diff --git a/render-test/linux-manifest.json b/render-test/linux-manifest.json new file mode 100644 index 0000000000..32a5afdbdb --- /dev/null +++ b/render-test/linux-manifest.json @@ -0,0 +1,7 @@ +{ + "base_test_path":"../mapbox-gl-js/test/integration", + "expectation_paths":["expected/render-tests"], + "ignore_paths":["../platform/node/test/ignores.json", "../render-test/linux-ignores.json", "../render-test/tests/should-fail.json"], + "vendor_path":"../vendor", + "asset_path": "../mapbox-gl-js/test/integration" +} \ No newline at end of file diff --git a/render-test/linux-probe-manifest.json b/render-test/linux-probe-manifest.json new file mode 100644 index 0000000000..0b2ca88988 --- /dev/null +++ b/render-test/linux-probe-manifest.json @@ -0,0 +1,7 @@ +{ + "probe_test_path":".", + "expectation_paths":["expected/render-tests"], + "ignore_paths":["../render-test/linux-ignores.json", "../render-test/tests/should-fail.json"], + "vendor_path":"../vendor", + "asset_path": "../mapbox-gl-js/test/integration" +} \ No newline at end of file diff --git a/render-test/mac-manifest.json b/render-test/mac-manifest.json new file mode 100644 index 0000000000..224df81298 --- /dev/null +++ b/render-test/mac-manifest.json @@ -0,0 +1,7 @@ +{ + "base_test_path":"../mapbox-gl-js/test/integration", + "expectation_paths":["expected/render-tests", "tests/mac"], + "ignore_paths":["../platform/node/test/ignores.json", "../render-test/mac-ignores.json", "../render-test/tests/should-fail.json"], + "vendor_path":"../vendor", + "asset_path": "../mapbox-gl-js/test/integration" +} \ No newline at end of file diff --git a/render-test/mac-probe-manifest.json b/render-test/mac-probe-manifest.json new file mode 100644 index 0000000000..f3cc56d0a8 --- /dev/null +++ b/render-test/mac-probe-manifest.json @@ -0,0 +1,7 @@ +{ + "probe_test_path":".", + "expectation_paths":["expected/render-tests", "tests/mac"], + "ignore_paths":["../render-test/mac-ignores.json", "../render-test/tests/should-fail.json"], + "vendor_path":"../vendor", + "asset_path": "../mapbox-gl-js/test/integration" +} \ No newline at end of file diff --git a/render-test/manifest_parser.cpp b/render-test/manifest_parser.cpp new file mode 100644 index 0000000000..f1884634e5 --- /dev/null +++ b/render-test/manifest_parser.cpp @@ -0,0 +1,400 @@ +#include "manifest_parser.hpp" +#include "filesystem.hpp" +#include "parser.hpp" + +#include + +#include +#include + +namespace { +std::string removeURLArguments(const std::string& url) { + std::string::size_type index = url.find('?'); + if (index != std::string::npos) { + return url.substr(0, index); + } + return url; +} + +std::string prependFileScheme(const std::string& url) { + static const std::string fileScheme("file://"); + return fileScheme + url; +} +} // namespace + +Manifest::Manifest() = default; +Manifest::~Manifest() = default; + +const std::vector& Manifest::getTestPaths() const { + return testPaths; +} +const std::vector>& Manifest::getIgnores() const { + return ignores; +} +const std::string& Manifest::getTestRootPath() const { + return testRootPath; +} +const std::string& Manifest::getManifestPath() const { + return manifestPath; +} + +void Manifest::doShuffle(uint32_t seed) { + std::seed_seq sequence{seed}; + std::mt19937 shuffler(sequence); + std::shuffle(testPaths.begin(), testPaths.end(), shuffler); +} + +std::string Manifest::localizeURL(const std::string& url) const { + static const std::regex regex{"local://"}; + if (auto vendorPath = getVendorPath(url, regex)) { + return *vendorPath; + } + return getIntegrationPath(url, "", regex).value_or(url); +} + +void Manifest::localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document) const { + if (root.HasMember("urls") && root["urls"].IsArray()) { + for (auto& urlValue : root["urls"].GetArray()) { + const std::string path = + prependFileScheme(localizeMapboxTilesetURL(urlValue.GetString()) + .value_or(localizeLocalURL(urlValue.GetString()).value_or(urlValue.GetString()))); + urlValue.Set(path, document.GetAllocator()); + } + } + + if (root.HasMember("url")) { + static const std::string image("image"); + static const std::string video("video"); + + mbgl::JSValue& urlValue = root["url"]; + const std::string path = + prependFileScheme(localizeMapboxTilesetURL(urlValue.GetString()) + .value_or(localizeLocalURL(urlValue.GetString()).value_or(urlValue.GetString()))); + urlValue.Set(path, document.GetAllocator()); + + if (root["type"].GetString() != image && root["type"].GetString() != video) { + const auto tilesetPath = std::string(urlValue.GetString()).erase(0u, 7u); // remove "file://" + auto maybeTileset = readJson(tilesetPath); + if (maybeTileset.is()) { + const auto& tileset = maybeTileset.get(); + assert(tileset.HasMember("tiles")); + root.AddMember("tiles", (mbgl::JSValue&)tileset["tiles"], document.GetAllocator()); + root.RemoveMember("url"); + } + } + } + + if (root.HasMember("tiles")) { + mbgl::JSValue& tilesValue = root["tiles"]; + assert(tilesValue.IsArray()); + for (auto& tileValue : tilesValue.GetArray()) { + const std::string path = prependFileScheme( + localizeMapboxTilesURL(tileValue.GetString()) + .value_or(localizeLocalURL(tileValue.GetString()) + .value_or(localizeHttpURL(tileValue.GetString()).value_or(tileValue.GetString())))); + tileValue.Set(path, document.GetAllocator()); + } + } + + if (root.HasMember("data") && root["data"].IsString()) { + mbgl::JSValue& dataValue = root["data"]; + const std::string path = + prependFileScheme(localizeLocalURL(dataValue.GetString()).value_or(dataValue.GetString())); + dataValue.Set(path, document.GetAllocator()); + } +} + +void Manifest::localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document) const { + if (root.HasMember("sources")) { + mbgl::JSValue& sourcesValue = root["sources"]; + for (auto& sourceProperty : sourcesValue.GetObject()) { + localizeSourceURLs(sourceProperty.value, document); + } + } + + if (root.HasMember("glyphs")) { + mbgl::JSValue& glyphsValue = root["glyphs"]; + const std::string path = prependFileScheme( + localizeMapboxFontsURL(glyphsValue.GetString()) + .value_or(localizeLocalURL(glyphsValue.GetString(), true).value_or(glyphsValue.GetString()))); + glyphsValue.Set(path, document.GetAllocator()); + } + + if (root.HasMember("sprite")) { + mbgl::JSValue& spriteValue = root["sprite"]; + const std::string path = prependFileScheme( + localizeMapboxSpriteURL(spriteValue.GetString()) + .value_or(localizeLocalURL(spriteValue.GetString()).value_or(spriteValue.GetString()))); + spriteValue.Set(path, document.GetAllocator()); + } +} + +mbgl::optional Manifest::localizeLocalURL(const std::string& url, bool glyphsPath) const { + static const std::regex regex{"local://"}; + if (auto vendorPath = getVendorPath(url, regex, glyphsPath)) { + return vendorPath; + } + return getIntegrationPath(url, "", regex, glyphsPath); +} + +mbgl::optional Manifest::localizeHttpURL(const std::string& url) const { + static const std::regex regex{"http://localhost:2900"}; + if (auto vendorPath = getVendorPath(url, regex)) { + return vendorPath; + } + return getIntegrationPath(url, "", regex); +} + +mbgl::optional Manifest::localizeMapboxSpriteURL(const std::string& url) const { + static const std::regex regex{"mapbox://"}; + return getIntegrationPath(url, "", regex); +} + +mbgl::optional Manifest::localizeMapboxFontsURL(const std::string& url) const { + static const std::regex regex{"mapbox://fonts"}; + return getIntegrationPath(url, "glyphs/", regex, true); +} + +mbgl::optional Manifest::localizeMapboxTilesURL(const std::string& url) const { + static const std::regex regex{"mapbox://"}; + if (auto vendorPath = getVendorPath(url, regex)) { + return vendorPath; + } + return getIntegrationPath(url, "tiles/", regex); +} + +mbgl::optional Manifest::localizeMapboxTilesetURL(const std::string& url) const { + static const std::regex regex{"mapbox://"}; + return getIntegrationPath(url, "tilesets/", regex); +} + +mbgl::optional Manifest::getVendorPath(const std::string& url, + const std::regex& regex, + bool glyphsPath) const { + mbgl::filesystem::path file = std::regex_replace(url, regex, vendorPath); + if (mbgl::filesystem::exists(file.parent_path())) { + return removeURLArguments(file.string()); + } + + if (glyphsPath && mbgl::filesystem::exists(file.parent_path().parent_path())) { + return removeURLArguments(file.string()); + } + + return mbgl::nullopt; +} + +mbgl::optional Manifest::getIntegrationPath(const std::string& url, + const std::string& parent, + const std::regex& regex, + bool glyphsPath) const { + mbgl::filesystem::path file = std::regex_replace(url, regex, assetPath + parent); + if (mbgl::filesystem::exists(file.parent_path())) { + return removeURLArguments(file.string()); + } + + if (glyphsPath && mbgl::filesystem::exists(file.parent_path().parent_path())) { + return removeURLArguments(file.string()); + } + + return mbgl::nullopt; +} + +namespace { +std::vector> parseIgnores(const std::vector& ignoresPaths) { + std::vector> ignores; + for (const auto& path : ignoresPaths) { + auto maybeIgnores = readJson(path); + if (!maybeIgnores.is()) { + continue; + } + for (const auto& property : maybeIgnores.get().GetObject()) { + const std::string ignore = {property.name.GetString(), property.name.GetStringLength()}; + const std::string reason = {property.value.GetString(), property.value.GetStringLength()}; + ignores.emplace_back(std::make_pair(ignore, reason)); + } + } + + return ignores; +} + +std::vector getTestExpectations(mbgl::filesystem::path testPath, + const mbgl::filesystem::path& testsRootPath, + std::vector expectationsPaths) { + std::vector expectations{std::move(testPath.remove_filename())}; + const auto& defaultTestExpectationsPath = expectations.front().string(); + + const std::regex regex{testsRootPath.string()}; + for (const auto& path : expectationsPaths) { + expectations.emplace_back(std::regex_replace(defaultTestExpectationsPath, regex, path.string())); + assert(!expectations.back().empty()); + } + + return expectations; +} + +mbgl::filesystem::path getValidPath(const std::string& manifestPath, const std::string& path) { + const static mbgl::filesystem::path BasePath{manifestPath}; + mbgl::filesystem::path result{path}; + if (result.is_relative()) { + result = BasePath / result; + } + if (mbgl::filesystem::exists(result)) { + return result; + } + mbgl::Log::Warning(mbgl::Event::General, "Invalid path is provoided inside the manifest file: %s", path.c_str()); + return mbgl::filesystem::path{}; +} + +} // namespace + +mbgl::optional ManifestParser::parseManifest(const std::string& manifestPath, + const std::vector& testNames, + const std::string& testFilter) { + Manifest manifest; + const auto filePath = mbgl::filesystem::path(manifestPath); + manifest.manifestPath = manifestPath.substr(0, manifestPath.find(filePath.filename())); + + auto contents = readJson(filePath); + if (!contents.is()) { + mbgl::Log::Error(mbgl::Event::General, "Provided manifest file: %s is not a valid json", filePath.c_str()); + return mbgl::nullopt; + } + + auto document = std::move(contents.get()); + if (document.HasMember("asset_path")) { + const auto& assetPathValue = document["asset_path"]; + if (!assetPathValue.IsString()) { + mbgl::Log::Warning( + mbgl::Event::General, "Invalid assetPath is provoided inside the manifest file: %s", filePath.c_str()); + return mbgl::nullopt; + } + manifest.assetPath = (getValidPath(manifest.manifestPath, assetPathValue.GetString()) / "").string(); + if (manifest.assetPath.empty()) { + return mbgl::nullopt; + } + } + if (document.HasMember("vendor_path")) { + const auto& vendorPathValue = document["vendor_path"]; + if (!vendorPathValue.IsString()) { + mbgl::Log::Warning( + mbgl::Event::General, "Invalid vendorPath is provoided inside the manifest file: %s", filePath.c_str()); + return mbgl::nullopt; + } + manifest.vendorPath = (getValidPath(manifest.manifestPath, vendorPathValue.GetString()) / "").string(); + if (manifest.vendorPath.empty()) { + return mbgl::nullopt; + } + } + mbgl::filesystem::path baseTestPath; + if (document.HasMember("base_test_path")) { + const auto& testPathValue = document["base_test_path"]; + if (!testPathValue.IsString()) { + mbgl::Log::Warning( + mbgl::Event::General, "Invalid testPath is provoided inside the manifest file: %s", filePath.c_str()); + return mbgl::nullopt; + } + baseTestPath = getValidPath(manifest.manifestPath, testPathValue.GetString()); + if (baseTestPath.empty()) { + return mbgl::nullopt; + } + } + mbgl::filesystem::path probeTestPath; + bool enbaleProbeTest{false}; + if (document.HasMember("probe_test_path")) { + const auto& testPathValue = document["probe_test_path"]; + if (!testPathValue.IsString()) { + mbgl::Log::Warning( + mbgl::Event::General, "Invalid testPath is provoided inside the manifest file: %s", filePath.c_str()); + return mbgl::nullopt; + } + probeTestPath = getValidPath(manifest.manifestPath, testPathValue.GetString()); + if (probeTestPath.empty()) { + return mbgl::nullopt; + } + enbaleProbeTest = true; + } + std::vector expectationPaths{}; + if (document.HasMember("expectation_paths")) { + const auto& expectationPathValue = document["expectation_paths"]; + if (!expectationPathValue.IsArray()) { + mbgl::Log::Warning(mbgl::Event::General, + "Provided expectation_paths inside the manifest file: %s is not a valid array", + filePath.c_str()); + return mbgl::nullopt; + } + for (const auto& value : expectationPathValue.GetArray()) { + if (!value.IsString()) { + mbgl::Log::Warning(mbgl::Event::General, + "Invalid expectation path item is provoided inside the manifest file: %s", + filePath.c_str()); + return mbgl::nullopt; + } + expectationPaths.emplace_back(getValidPath(manifest.manifestPath, value.GetString())); + if (expectationPaths.back().empty()) { + return mbgl::nullopt; + } + } + } + std::vector ignorePaths{}; + if (document.HasMember("ignore_paths")) { + const auto& ignorePathValue = document["ignore_paths"]; + if (!ignorePathValue.IsArray()) { + mbgl::Log::Warning(mbgl::Event::General, + "Provided ignore_paths inside the manifest file: %s is not a valid array", + filePath.c_str()); + return mbgl::nullopt; + } + for (const auto& value : ignorePathValue.GetArray()) { + if (!value.IsString()) { + mbgl::Log::Warning(mbgl::Event::General, + "Invalid ignore path item is provoided inside the manifest file: %s", + filePath.c_str()); + return mbgl::nullopt; + } + ignorePaths.emplace_back(getValidPath(manifest.manifestPath, value.GetString())); + if (ignorePaths.back().empty()) { + return mbgl::nullopt; + } + } + manifest.ignores = parseIgnores(ignorePaths); + } + + manifest.testRootPath = enbaleProbeTest ? probeTestPath.string() : baseTestPath.string(); + if (manifest.testRootPath.back() == '/') { + manifest.testRootPath.pop_back(); + } + if (manifest.manifestPath.back() == '/') { + manifest.manifestPath.pop_back(); + } + + std::vector paths; + for (const auto& id : testNames) { + paths.emplace_back(manifest.testRootPath + "/" + id); + } + if (paths.empty()) { + paths.emplace_back(manifest.testRootPath); + } + + // Recursively traverse through the test paths and collect test directories containing "style.json". + auto& testPaths = manifest.testPaths; + testPaths.reserve(paths.size()); + for (const auto& path : paths) { + if (!mbgl::filesystem::exists(path)) { + mbgl::Log::Warning( + mbgl::Event::General, "Provided test folder '%s' does not exist.", path.string().c_str()); + continue; + } + for (auto& testPath : mbgl::filesystem::recursive_directory_iterator(path)) { + // Skip paths that fail regexp match. + if (!testFilter.empty() && !std::regex_match(testPath.path().string(), std::regex(testFilter))) { + continue; + } + + if (testPath.path().filename() == "style.json") { + testPaths.emplace_back(testPath, getTestExpectations(testPath, path, expectationPaths)); + } + } + } + + return mbgl::optional(manifest); +} diff --git a/render-test/manifest_parser.hpp b/render-test/manifest_parser.hpp new file mode 100644 index 0000000000..bc5adf1091 --- /dev/null +++ b/render-test/manifest_parser.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "metadata.hpp" + +#include +#include + +#include +#include +#include +#include + +class Manifest { +public: + Manifest(); + ~Manifest(); + const std::vector>& getIgnores() const; + const std::vector& getTestPaths() const; + const std::string& getTestRootPath() const; + const std::string& getManifestPath() const; + void doShuffle(uint32_t seed); + + std::string localizeURL(const std::string& url) const; + void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document) const; + void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document) const; + +private: + friend class ManifestParser; + mbgl::optional localizeLocalURL(const std::string& url, bool glyphsPath = false) const; + mbgl::optional localizeHttpURL(const std::string& url) const; + mbgl::optional localizeMapboxSpriteURL(const std::string& url) const; + mbgl::optional localizeMapboxFontsURL(const std::string& url) const; + mbgl::optional localizeMapboxTilesURL(const std::string& url) const; + mbgl::optional localizeMapboxTilesetURL(const std::string& url) const; + mbgl::optional getVendorPath(const std::string& url, + const std::regex& regex, + bool glyphsPath = false) const; + mbgl::optional getIntegrationPath(const std::string& url, + const std::string& parent, + const std::regex& regex, + bool glyphsPath = false) const; + std::string manifestPath; + std::string testRootPath; + std::string vendorPath; + std::string assetPath; + std::vector> ignores; + std::vector testPaths; +}; + +class ManifestParser { +public: + static mbgl::optional parseManifest(const std::string& manifestPath, + const std::vector& testNames, + const std::string& testFilter); +}; diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 11a42f3202..5a91fc7a58 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include #include #include @@ -23,8 +21,8 @@ #include "parser.hpp" #include "runner.hpp" -#include #include +#include namespace { @@ -83,101 +81,6 @@ const char* resultsHeaderButtons = R"HTML( )HTML"; -std::string removeURLArguments(const std::string &url) { - std::string::size_type index = url.find('?'); - if (index != std::string::npos) { - return url.substr(0, index); - } - return url; -} - -std::string prependFileScheme(const std::string &url) { - static const std::string fileScheme("file://"); - return fileScheme + url; -} - -mbgl::optional getVendorPath(const std::string& url, - const std::regex& regex, - const std::string& testRootPath, - bool glyphsPath = false) { - static const mbgl::filesystem::path vendorPath = getValidPath(testRootPath, std::string("vendor/")); - - mbgl::filesystem::path file = std::regex_replace(url, regex, vendorPath.string()); - if (mbgl::filesystem::exists(file.parent_path())) { - return removeURLArguments(file.string()); - } - - if (glyphsPath && mbgl::filesystem::exists(file.parent_path().parent_path())) { - return removeURLArguments(file.string()); - } - - return {}; -} - -mbgl::optional getIntegrationPath(const std::string& url, - const std::string& parent, - const std::regex& regex, - const std::string& testRootPath, - bool glyphsPath = false) { - static const mbgl::filesystem::path integrationPath = - getValidPath(testRootPath, std::string("mapbox-gl-js/test/integration/")); - - mbgl::filesystem::path file = std::regex_replace(url, regex, integrationPath.string() + parent); - if (mbgl::filesystem::exists(file.parent_path())) { - return removeURLArguments(file.string()); - } - - if (glyphsPath && mbgl::filesystem::exists(file.parent_path().parent_path())) { - return removeURLArguments(file.string()); - } - - return {}; -} - -mbgl::optional localizeLocalURL(const std::string& url, - const std::string& testRootPath, - bool glyphsPath = false) { - static const std::regex regex{"local://"}; - if (auto vendorPath = getVendorPath(url, regex, testRootPath, glyphsPath)) { - return vendorPath; - } else { - return getIntegrationPath(url, "", regex, testRootPath, glyphsPath); - } -} - -mbgl::optional localizeHttpURL(const std::string& url, const std::string& testRootPath) { - static const std::regex regex{"http://localhost:2900"}; - if (auto vendorPath = getVendorPath(url, regex, testRootPath)) { - return vendorPath; - } else { - return getIntegrationPath(url, "", regex, testRootPath); - } -} - -mbgl::optional localizeMapboxSpriteURL(const std::string& url, const std::string& testRootPath) { - static const std::regex regex{"mapbox://"}; - return getIntegrationPath(url, "", regex, testRootPath); -} - -mbgl::optional localizeMapboxFontsURL(const std::string& url, const std::string& testRootPath) { - static const std::regex regex{"mapbox://fonts"}; - return getIntegrationPath(url, "glyphs/", regex, testRootPath, true); -} - -mbgl::optional localizeMapboxTilesURL(const std::string& url, const std::string& testRootPath) { - static const std::regex regex{"mapbox://"}; - if (auto vendorPath = getVendorPath(url, regex, testRootPath)) { - return vendorPath; - } else { - return getIntegrationPath(url, "tiles/", regex, testRootPath); - } -} - -mbgl::optional localizeMapboxTilesetURL(const std::string& url, const std::string& testRootPath) { - static const std::regex regex{"mapbox://"}; - return getIntegrationPath(url, "tilesets/", regex, testRootPath); -} - void writeJSON(rapidjson::PrettyWriter& writer, const mbgl::Value& value) { value.match([&writer](const mbgl::NullValue&) { writer.Null(); }, [&writer](bool b) { writer.Bool(b); }, @@ -205,33 +108,6 @@ void writeJSON(rapidjson::PrettyWriter& writer, const m } // namespace -static const mbgl::filesystem::path DefaultRootPath{std::string(TEST_RUNNER_ROOT_PATH)}; - -const mbgl::filesystem::path getValidPath(const std::string& basePath, const std::string& subPath) { - auto filePath = mbgl::filesystem::path(basePath) / subPath; - if (mbgl::filesystem::exists(filePath)) { - return filePath; - } - // Fall back to check default path - filePath = DefaultRootPath / subPath; - if (mbgl::filesystem::exists(filePath)) { - return filePath; - } - mbgl::Log::Warning(mbgl::Event::General, "Failed to find path: %s", subPath.c_str()); - return mbgl::filesystem::path{}; -} - -/// Returns path of the render test cases directory. -const std::string getTestPath(const std::string& rootTestPath) { - // Check if sub-directory exits or not - auto testBasePath = mbgl::filesystem::path(rootTestPath) / ("mapbox-gl-js/test/integration"); - if (mbgl::filesystem::exists(testBasePath)) { - return testBasePath.string(); - } - // Use root test path for further processing - return rootTestPath; -} - std::string toJSON(const mbgl::Value& value, unsigned indent, bool singleLine) { rapidjson::StringBuffer buffer; rapidjson::PrettyWriter writer(buffer); @@ -284,7 +160,7 @@ JSONReply readJson(const mbgl::filesystem::path& jsonPath) { return { mbgl::formatJSONParseError(document) }; } - return { std::move(document) }; + return {std::move(document)}; } std::string serializeJsonValue(const mbgl::JSValue& value) { @@ -392,170 +268,6 @@ std::vector readExpectedJSONEntries(const mbgl::filesystem::path& b return readExpectedEntries(regex, base); } -namespace { - -std::vector getTestExpectations(mbgl::filesystem::path testPath, - const mbgl::filesystem::path& testsRootPath, - std::vector expectationsPaths) { - std::vector expectations{std::move(testPath.remove_filename())}; - const auto& defaultTestExpectationsPath = expectations.front().string(); - - const std::regex regex{testsRootPath.string()}; - for (const auto& path : expectationsPaths) { - expectations.emplace_back(std::regex_replace(defaultTestExpectationsPath, regex, path.string())); - assert(!expectations.back().empty()); - } - - return expectations; -} - -} // namespace - -ArgumentsTuple parseArguments(int argc, char** argv) { - args::ArgumentParser argumentParser("Mapbox GL Test Runner"); - - args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", { 'h', "help" }); - - args::Flag recycleMapFlag(argumentParser, "recycle map", "Toggle reusing the map object", {'r', "recycle-map"}); - args::Flag shuffleFlag(argumentParser, "shuffle", "Toggle shuffling the tests order", {'s', "shuffle"}); - args::ValueFlag seedValue(argumentParser, "seed", "Shuffle seed (default: random)", - { "seed" }); - args::ValueFlag testPathValue(argumentParser, "rootPath", "Test root rootPath", {'p', "rootPath"}); - args::ValueFlag testFilterValue(argumentParser, "filter", "Test filter regex", {'f', "filter"}); - args::ValueFlag expectationsPathValue( - argumentParser, "expectationsPath", "Test expectations path", {'e', "expectationsPath"}); - args::ValueFlag ignoresPathValue( - argumentParser, "ignoresPath", "Test ignore list path", {'i', "ignoresPath"}); - args::PositionalList testNameValues(argumentParser, "URL", "Test name(s)"); - - try { - argumentParser.ParseCLI(argc, argv); - } catch (const args::Help&) { - std::ostringstream stream; - stream << argumentParser; - mbgl::Log::Info(mbgl::Event::General, stream.str()); - exit(0); - } catch (const args::ParseError& e) { - std::ostringstream stream; - stream << argumentParser; - mbgl::Log::Info(mbgl::Event::General, stream.str()); - mbgl::Log::Error(mbgl::Event::General, e.what()); - exit(1); - } catch (const args::ValidationError& e) { - std::ostringstream stream; - stream << argumentParser; - mbgl::Log::Info(mbgl::Event::General, stream.str()); - mbgl::Log::Error(mbgl::Event::General, e.what()); - exit(2); - } catch (const std::regex_error& e) { - mbgl::Log::Error(mbgl::Event::General, "Invalid filter regular expression: %s", e.what()); - exit(3); - } - - const auto testRootPath = testPathValue ? args::get(testPathValue) : std::string{TEST_RUNNER_ROOT_PATH}; - mbgl::filesystem::path rootPath{testRootPath}; - if (!mbgl::filesystem::exists(rootPath)) { - mbgl::Log::Error( - mbgl::Event::General, "Provided test rootPath '%s' does not exist.", rootPath.string().c_str()); - exit(4); - } - std::vector expectationsPaths; - if (expectationsPathValue) { - auto expectationsPath = mbgl::filesystem::path(testRootPath) / args::get(expectationsPathValue); - if (!mbgl::filesystem::exists(expectationsPath)) { - mbgl::Log::Error(mbgl::Event::General, - "Provided expectationsPath '%s' does not exist.", - expectationsPath.string().c_str()); - exit(5); - } - expectationsPaths.emplace_back(std::move(expectationsPath)); - } - - std::string ignoresPath{}; - if (ignoresPathValue) { - auto path = mbgl::filesystem::path(testRootPath) / args::get(ignoresPathValue); - if (!mbgl::filesystem::exists(path)) { - mbgl::Log::Error( - mbgl::Event::General, "Provided ignore list path '%s' does not exist.", path.string().c_str()); - exit(6); - } - ignoresPath = path.string(); - } - - std::vector paths; - auto testBasePath = mbgl::filesystem::path(getTestPath(testRootPath)); - for (const auto& id : args::get(testNameValues)) { - paths.emplace_back(testBasePath / id); - } - - if (paths.empty()) { - paths.emplace_back(testBasePath); - } - - // Recursively traverse through the test paths and collect test directories containing "style.json". - std::vector testPaths; - testPaths.reserve(paths.size()); - for (const auto& path : paths) { - if (!mbgl::filesystem::exists(path)) { - mbgl::Log::Warning(mbgl::Event::General, "Provided test folder '%s' does not exist.", path.string().c_str()); - continue; - } - for (auto& testPath : mbgl::filesystem::recursive_directory_iterator(path)) { - // Skip paths that fail regexp match. - if (testFilterValue && !std::regex_match(testPath.path().string(), args::get(testFilterValue))) { - continue; - } - - if (testPath.path().filename() == "style.json") { - testPaths.emplace_back(testPath, getTestExpectations(testPath, path, expectationsPaths)); - } - } - } - - return ArgumentsTuple{recycleMapFlag ? args::get(recycleMapFlag) : false, - shuffleFlag ? args::get(shuffleFlag) : false, - seedValue ? args::get(seedValue) : 1u, - testRootPath, - ignoresPath, - std::move(testPaths)}; -} - -std::vector> parseIgnores(const std::string& testRootPath, - const std::string& ignoresPath) { - std::vector> ignores; - auto mainIgnoresPath = getValidPath(testRootPath, "platform/node/test/ignores.json"); - - mbgl::filesystem::path platformSpecificIgnores; - mbgl::filesystem::path ownTestsIgnores = getValidPath(testRootPath, "render-test/tests/should-fail.json"); - -#ifdef __APPLE__ - platformSpecificIgnores = getValidPath(testRootPath, "render-test/mac-ignores.json"); -#elif __linux__ - platformSpecificIgnores = getValidPath(testRootPath, "render-test/linux-ignores.json"); -#endif - - std::vector ignoresPaths = {mainIgnoresPath, platformSpecificIgnores, ownTestsIgnores}; - - if (!ignoresPath.empty()) { - ignoresPaths.emplace_back(ignoresPath); - } - for (const auto& path : ignoresPaths) { - auto maybeIgnores = readJson(path); - if (!maybeIgnores.is()) { - continue; - } - for (const auto& property : maybeIgnores.get().GetObject()) { - const std::string ignore = { property.name.GetString(), - property.name.GetStringLength() }; - const std::string reason = { property.value.GetString(), - property.value.GetStringLength() }; - ignores.emplace_back(std::make_pair(ignore, reason)); - } - } - - return ignores; -} - TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { TestMetrics result; @@ -601,7 +313,7 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { std::string mark{probeValue[0].GetString(), probeValue[0].GetStringLength()}; assert(!mark.empty()); result.memory.emplace(std::piecewise_construct, - std::forward_as_tuple(std::move(mark)), + std::forward_as_tuple(std::move(mark)), std::forward_as_tuple(probeValue[1].GetUint64(), probeValue[2].GetUint64())); } } @@ -645,7 +357,7 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { return result; } -TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRootPath) { +TestMetadata parseTestMetadata(const TestPaths& paths, const Manifest& manifest) { TestMetadata metadata; metadata.paths = paths; @@ -656,7 +368,7 @@ TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRo } metadata.document = std::move(maybeJson.get()); - localizeStyleURLs(metadata.document, metadata.document, testRootPath); + manifest.localizeStyleURLs(metadata.document, metadata.document); if (!metadata.document.HasMember("metadata")) { mbgl::Log::Warning(mbgl::Event::ParseStyle, "Style has no 'metadata': %s", paths.stylePath.c_str()); @@ -665,8 +377,7 @@ TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRo const mbgl::JSValue& metadataValue = metadata.document["metadata"]; if (!metadataValue.HasMember("test")) { - mbgl::Log::Warning(mbgl::Event::ParseStyle, "Style has no 'metadata.test': %s", - paths.stylePath.c_str()); + mbgl::Log::Warning(mbgl::Event::ParseStyle, "Style has no 'metadata.test': %s", paths.stylePath.c_str()); return metadata; } @@ -694,8 +405,8 @@ TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRo if (testValue.HasMember("description")) { assert(testValue["description"].IsString()); - metadata.description = std::string{ testValue["description"].GetString(), - testValue["description"].GetStringLength() }; + metadata.description = + std::string{testValue["description"].GetString(), testValue["description"].GetStringLength()}; } if (testValue.HasMember("mapMode")) { @@ -802,8 +513,9 @@ std::string encodeBase64(const std::string& data) { } std::string createResultItem(const TestMetadata& metadata, bool hasFailedTests) { - const bool shouldHide = (hasFailedTests && metadata.status == "passed") || (metadata.status.find("ignored") != std::string::npos); - + const bool shouldHide = + (hasFailedTests && metadata.status == "passed") || (metadata.status.find("ignored") != std::string::npos); + std::string html; html.append("
\n"); html.append(R"(

" + metadata.status + " " + metadata.id + "

\n"); @@ -918,91 +630,3 @@ std::string createResultPage(const TestStatistics& stats, const std::vector(path, document.GetAllocator()); - } - } - - if (root.HasMember("url")) { - static const std::string image("image"); - static const std::string video("video"); - - mbgl::JSValue& urlValue = root["url"]; - const std::string path = prependFileScheme( - localizeMapboxTilesetURL(urlValue.GetString(), testRootPath) - .value_or(localizeLocalURL(urlValue.GetString(), testRootPath).value_or(urlValue.GetString()))); - urlValue.Set(path, document.GetAllocator()); - - if (root["type"].GetString() != image && root["type"].GetString() != video) { - const auto tilesetPath = std::string(urlValue.GetString()).erase(0u, 7u); // remove "file://" - auto maybeTileset = readJson(tilesetPath); - if (maybeTileset.is()) { - const auto& tileset = maybeTileset.get(); - assert(tileset.HasMember("tiles")); - root.AddMember("tiles", (mbgl::JSValue&)tileset["tiles"], document.GetAllocator()); - root.RemoveMember("url"); - } - } - } - - if (root.HasMember("tiles")) { - mbgl::JSValue& tilesValue = root["tiles"]; - assert(tilesValue.IsArray()); - for (auto& tileValue : tilesValue.GetArray()) { - const std::string path = - prependFileScheme(localizeMapboxTilesURL(tileValue.GetString(), testRootPath) - .value_or(localizeLocalURL(tileValue.GetString(), testRootPath) - .value_or(localizeHttpURL(tileValue.GetString(), testRootPath) - .value_or(tileValue.GetString())))); - tileValue.Set(path, document.GetAllocator()); - } - } - - if (root.HasMember("data") && root["data"].IsString()) { - mbgl::JSValue& dataValue = root["data"]; - const std::string path = - prependFileScheme(localizeLocalURL(dataValue.GetString(), testRootPath).value_or(dataValue.GetString())); - dataValue.Set(path, document.GetAllocator()); - } -} - -void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document, const std::string& testRootPath) { - if (root.HasMember("sources")) { - mbgl::JSValue& sourcesValue = root["sources"]; - for (auto& sourceProperty : sourcesValue.GetObject()) { - localizeSourceURLs(sourceProperty.value, document, testRootPath); - } - } - - if (root.HasMember("glyphs")) { - mbgl::JSValue& glyphsValue = root["glyphs"]; - const std::string path = prependFileScheme( - localizeMapboxFontsURL(glyphsValue.GetString(), testRootPath) - .value_or( - localizeLocalURL(glyphsValue.GetString(), testRootPath, true).value_or(glyphsValue.GetString()))); - glyphsValue.Set(path, document.GetAllocator()); - } - - if (root.HasMember("sprite")) { - mbgl::JSValue& spriteValue = root["sprite"]; - const std::string path = prependFileScheme( - localizeMapboxSpriteURL(spriteValue.GetString(), testRootPath) - .value_or(localizeLocalURL(spriteValue.GetString(), testRootPath).value_or(spriteValue.GetString()))); - spriteValue.Set(path, document.GetAllocator()); - } -} diff --git a/render-test/parser.hpp b/render-test/parser.hpp index 1985b9cffc..3d79ac668a 100644 --- a/render-test/parser.hpp +++ b/render-test/parser.hpp @@ -5,15 +5,15 @@ #include #include -#include #include +#include #include +class Manifest; + using ErrorMessage = std::string; using JSONReply = mbgl::variant; -using ArgumentsTuple = std::tuple>; - JSONReply readJson(const mbgl::filesystem::path&); std::string serializeJsonValue(const mbgl::JSValue&); std::string serializeMetrics(const TestMetrics&); @@ -23,21 +23,9 @@ std::vector readExpectedJSONEntries(const mbgl::filesystem::path& b TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path); -const std::string getTestPath(const std::string& rootTestPath); -const mbgl::filesystem::path getValidPath(const std::string& basePath, const std::string& subPath); - -ArgumentsTuple parseArguments(int argc, char** argv); -std::vector> parseIgnores(const std::string& testRootPath, - const std::string& ignoresPath); - -TestMetadata parseTestMetadata(const TestPaths& paths, const std::string& testRootPath); +TestMetadata parseTestMetadata(const TestPaths& paths, const Manifest& manifest); std::string createResultPage(const TestStatistics&, const std::vector&, bool shuffle, uint32_t seed); -std::string localizeURL(const std::string& url, const std::string& testPath); - std::string toJSON(const mbgl::Value& value, unsigned indent, bool singleLine); std::string toJSON(const std::vector& features, unsigned indent, bool singleLine); - -void localizeSourceURLs(mbgl::JSValue& root, mbgl::JSDocument& document, const std::string& testPath); -void localizeStyleURLs(mbgl::JSValue& root, mbgl::JSDocument& document, const std::string& testPath); diff --git a/render-test/render_test.cpp b/render-test/render_test.cpp index 2cf3f5fd65..38d6c15f3f 100644 --- a/render-test/render_test.cpp +++ b/render-test/render_test.cpp @@ -2,14 +2,16 @@ #include #include +#include #include +#include + +#include "manifest_parser.hpp" #include "metadata.hpp" #include "parser.hpp" #include "runner.hpp" -#include - #define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_YELLOW "\x1b[33m" @@ -37,38 +39,97 @@ void operator delete(void* ptr, size_t) noexcept { } #endif +namespace { +using ArgumentsTuple = std::tuple, std::string>; +ArgumentsTuple parseArguments(int argc, char** argv) { + args::ArgumentParser argumentParser("Mapbox GL Test Runner"); + + args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {'h', "help"}); + + args::Flag recycleMapFlag(argumentParser, "recycle map", "Toggle reusing the map object", {'r', "recycle-map"}); + args::Flag shuffleFlag(argumentParser, "shuffle", "Toggle shuffling the tests order", {'s', "shuffle"}); + args::ValueFlag seedValue(argumentParser, "seed", "Shuffle seed (default: random)", {"seed"}); + args::ValueFlag testPathValue( + argumentParser, "manifestPath", "Test manifest file path", {'p', "manifestPath"}); + args::ValueFlag testFilterValue(argumentParser, "filter", "Test filter regex", {'f', "filter"}); + args::PositionalList testNameValues(argumentParser, "URL", "Test name(s)"); + + try { + argumentParser.ParseCLI(argc, argv); + } catch (const args::Help&) { + std::ostringstream stream; + stream << argumentParser; + mbgl::Log::Info(mbgl::Event::General, stream.str()); + exit(0); + } catch (const args::ParseError& e) { + std::ostringstream stream; + stream << argumentParser; + mbgl::Log::Info(mbgl::Event::General, stream.str()); + mbgl::Log::Error(mbgl::Event::General, e.what()); + exit(1); + } catch (const args::ValidationError& e) { + std::ostringstream stream; + stream << argumentParser; + mbgl::Log::Info(mbgl::Event::General, stream.str()); + mbgl::Log::Error(mbgl::Event::General, e.what()); + exit(2); + } catch (const std::regex_error& e) { + mbgl::Log::Error(mbgl::Event::General, "Invalid filter regular expression: %s", e.what()); + exit(3); + } + + mbgl::filesystem::path manifestPath{testPathValue ? args::get(testPathValue) : std::string{TEST_RUNNER_ROOT_PATH}}; + if (!mbgl::filesystem::exists(manifestPath) || !manifestPath.has_filename()) { + mbgl::Log::Error(mbgl::Event::General, + "Provided test manifest file path '%s' does not exist", + manifestPath.string().c_str()); + exit(4); + } + + auto testNames = testNameValues ? args::get(testNameValues) : std::vector{}; + auto testFilter = testFilterValue ? args::get(testFilterValue) : std::string{}; + const auto shuffle = shuffleFlag ? args::get(shuffleFlag) : false; + const auto seed = seedValue ? args::get(seedValue) : 1u; + return ArgumentsTuple{recycleMapFlag ? args::get(recycleMapFlag) : false, + shuffle, + seed, + manifestPath.string(), + std::move(testNames), + std::move(testFilter)}; +} +} // namespace namespace mbgl { int runRenderTests(int argc, char** argv) { bool recycleMap; bool shuffle; uint32_t seed; - std::string testRootPath; - std::string ignoresPath; - std::vector testPaths; - - std::tie(recycleMap, shuffle, seed, testRootPath, ignoresPath, testPaths) = parseArguments(argc, argv); - - const auto ignores = parseIgnores(testRootPath, ignoresPath); - + std::string manifestPath; + std::vector testNames; + std::string testFilter; + + std::tie(recycleMap, shuffle, seed, manifestPath, testNames, testFilter) = parseArguments(argc, argv); + auto manifestData = ManifestParser::parseManifest(manifestPath, testNames, testFilter); + if (!manifestData) { + exit(5); + } + mbgl::util::RunLoop runLoop; + TestRunner runner(std::move(*manifestData)); if (shuffle) { printf(ANSI_COLOR_YELLOW "Shuffle seed: %d" ANSI_COLOR_RESET "\n", seed); - - std::seed_seq sequence { seed }; - std::mt19937 shuffler(sequence); - std::shuffle(testPaths.begin(), testPaths.end(), shuffler); + runner.doShuffle(seed); } - mbgl::util::RunLoop runLoop; - TestRunner runner(testRootPath); - + const auto& manifest = runner.getManifest(); + const auto& ignores = manifest.getIgnores(); + const auto& testPaths = manifest.getTestPaths(); std::vector metadatas; metadatas.reserve(testPaths.size()); TestStatistics stats; for (auto& testPath : testPaths) { - TestMetadata metadata = parseTestMetadata(testPath, testRootPath); + TestMetadata metadata = parseTestMetadata(testPath, manifest); if (!recycleMap) { runner.reset(); @@ -78,7 +139,7 @@ int runRenderTests(int argc, char** argv) { std::string& status = metadata.status; std::string& color = metadata.color; - const std::string::size_type rootLength = getTestPath(testRootPath).length(); + const std::string::size_type rootLength = manifest.getTestRootPath().length(); id = testPath.defaultExpectations(); id = id.substr(rootLength + 1, id.length() - rootLength - 2); @@ -138,13 +199,14 @@ int runRenderTests(int argc, char** argv) { metadatas.push_back(std::move(metadata)); } - + const auto& testRootPath = manifest.getManifestPath(); + const auto resultPath = + testRootPath + "/" + (testNames.empty() ? "render-tests" : testNames.front()) + "_index.html"; std::string resultsHTML = createResultPage(stats, metadatas, shuffle, seed); - mbgl::util::write_file(testRootPath + "/index.html", resultsHTML); + mbgl::util::write_file(resultPath, resultsHTML); - const uint32_t count = stats.erroredTests + stats.failedTests + - stats.ignoreFailedTests + stats.ignorePassedTests + - stats.passedTests; + const uint32_t count = + stats.erroredTests + stats.failedTests + stats.ignoreFailedTests + stats.ignorePassedTests + stats.passedTests; if (stats.passedTests) { printf(ANSI_COLOR_GREEN "%u passed (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.passedTests, 100.0 * stats.passedTests / count); @@ -162,7 +224,7 @@ int runRenderTests(int argc, char** argv) { printf(ANSI_COLOR_RED "%u errored (%.1lf%%)" ANSI_COLOR_RESET "\n", stats.erroredTests, 100.0 * stats.erroredTests / count); } - printf("Results at: %s%s\n", testRootPath.c_str(), "/index.html"); + printf("Results at: %s\n", resultPath.c_str()); return stats.failedTests + stats.erroredTests == 0 ? 0 : 1; } diff --git a/render-test/runner.cpp b/render-test/runner.cpp index 4c0967a9e9..e882e394be 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -101,7 +101,15 @@ std::string simpleDiff(const Value& result, const Value& expected) { return diff.str(); } -TestRunner::TestRunner(const std::string& testRootPath_) : maps(), testRootPath(testRootPath_) {} +TestRunner::TestRunner(Manifest manifest_) : manifest(std::move(manifest_)) {} + +const Manifest& TestRunner::getManifest() const { + return manifest; +} + +void TestRunner::doShuffle(uint32_t seed) { + manifest.doShuffle(seed); +} bool TestRunner::checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, std::vector&& features, @@ -487,7 +495,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { std::string imagePath = operationArray[2].GetString(); imagePath.erase(std::remove(imagePath.begin(), imagePath.end(), '"'), imagePath.end()); - const mbgl::filesystem::path filePath = mbgl::filesystem::path(getTestPath(testRootPath)) / imagePath; + const mbgl::filesystem::path filePath = mbgl::filesystem::path(manifest.getTestRootPath()) / imagePath; mbgl::optional maybeImage = mbgl::util::readFile(filePath.string()); if (!maybeImage) { @@ -507,15 +515,15 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { // setStyle assert(operationArray.Size() >= 2u); if (operationArray[1].IsString()) { - std::string stylePath = localizeURL(operationArray[1].GetString(), testRootPath); + std::string stylePath = manifest.localizeURL(operationArray[1].GetString()); auto maybeStyle = readJson(stylePath); if (maybeStyle.is()) { auto& style = maybeStyle.get(); - localizeStyleURLs((mbgl::JSValue&)style, style, testRootPath); + manifest.localizeStyleURLs((mbgl::JSValue&)style, style); map.getStyle().loadJSON(serializeJsonValue(style)); } } else { - localizeStyleURLs(operationArray[1], metadata.document, testRootPath); + manifest.localizeStyleURLs(operationArray[1], metadata.document); map.getStyle().loadJSON(serializeJsonValue(operationArray[1])); } } else if (operationArray[0].GetString() == setCenterOp) { @@ -616,7 +624,7 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { assert(operationArray[1].IsString()); assert(operationArray[2].IsObject()); - localizeSourceURLs(operationArray[2], metadata.document, testRootPath); + manifest.localizeSourceURLs(operationArray[2], metadata.document); mbgl::style::conversion::Error error; auto converted = mbgl::style::conversion::convert>(operationArray[2], error, operationArray[1].GetString()); diff --git a/render-test/runner.hpp b/render-test/runner.hpp index 3efd17bf1e..bc97f8300b 100644 --- a/render-test/runner.hpp +++ b/render-test/runner.hpp @@ -3,6 +3,8 @@ #include #include +#include "manifest_parser.hpp" + #include #include @@ -11,11 +13,14 @@ struct TestMetadata; class TestRunner { public: - TestRunner() = default; - explicit TestRunner(const std::string& testRootPath); + explicit TestRunner(Manifest); bool run(TestMetadata&); void reset(); + // Manifest + const Manifest& getManifest() const; + void doShuffle(uint32_t seed); + private: bool runOperations(const std::string& key, TestMetadata&); bool checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, @@ -32,5 +37,5 @@ private: mbgl::Map map; }; std::unordered_map> maps; - std::string testRootPath{TEST_RUNNER_ROOT_PATH}; + Manifest manifest; }; -- cgit v1.2.1 From fb062bb23e66af3d5a889b767aae380884b259e5 Mon Sep 17 00:00:00 2001 From: Mikko Pulkki Date: Tue, 15 Oct 2019 12:09:21 +0300 Subject: [render-test] Add resource usage tracking to gfx context --- include/mbgl/gfx/rendering_stats.hpp | 22 +++++++++++ next/CMakeLists.txt | 5 +++ .../default/src/mbgl/gfx/headless_frontend.cpp | 1 + src/core-files.json | 5 +++ src/mbgl/gfx/context.hpp | 7 +++- src/mbgl/gfx/rendering_stats.cpp | 12 ++++++ src/mbgl/gl/context.cpp | 30 +++++++++++++-- src/mbgl/gl/context.hpp | 4 ++ src/mbgl/gl/index_buffer_resource.cpp | 14 +++++++ src/mbgl/gl/index_buffer_resource.hpp | 5 ++- src/mbgl/gl/object.cpp | 2 + src/mbgl/gl/texture_resource.cpp | 45 ++++++++++++++++++++++ src/mbgl/gl/texture_resource.hpp | 7 +++- src/mbgl/gl/upload_pass.cpp | 12 ++++-- src/mbgl/gl/vertex_buffer_resource.cpp | 14 +++++++ src/mbgl/gl/vertex_buffer_resource.hpp | 5 ++- 16 files changed, 176 insertions(+), 14 deletions(-) create mode 100644 include/mbgl/gfx/rendering_stats.hpp create mode 100644 src/mbgl/gfx/rendering_stats.cpp create mode 100644 src/mbgl/gl/index_buffer_resource.cpp create mode 100644 src/mbgl/gl/texture_resource.cpp create mode 100644 src/mbgl/gl/vertex_buffer_resource.cpp diff --git a/include/mbgl/gfx/rendering_stats.hpp b/include/mbgl/gfx/rendering_stats.hpp new file mode 100644 index 0000000000..8fb01a5825 --- /dev/null +++ b/include/mbgl/gfx/rendering_stats.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace mbgl { +namespace gfx { + +struct RenderingStats { + RenderingStats() = default; + bool isZero() const; + + int numDrawCalls; + int numActiveTextures; + int numCreatedTextures; + int numBuffers; + int numFrameBuffers; + + int memTextures; + int memIndexBuffers; + int memVertexBuffers; +}; + +} // namespace gfx +} // namespace mbgl \ No newline at end of file diff --git a/next/CMakeLists.txt b/next/CMakeLists.txt index 524a86e189..924761ad85 100644 --- a/next/CMakeLists.txt +++ b/next/CMakeLists.txt @@ -70,6 +70,7 @@ add_library( ${MBGL_ROOT}/include/mbgl/gfx/backend_scope.hpp ${MBGL_ROOT}/include/mbgl/gfx/renderable.hpp ${MBGL_ROOT}/include/mbgl/gfx/renderer_backend.hpp + ${MBGL_ROOT}/include/mbgl/gfx/rendering_stats.hpp ${MBGL_ROOT}/include/mbgl/gl/renderable_resource.hpp ${MBGL_ROOT}/include/mbgl/gl/renderer_backend.hpp ${MBGL_ROOT}/include/mbgl/layermanager/background_layer_factory.hpp @@ -285,6 +286,7 @@ add_library( ${MBGL_ROOT}/src/mbgl/gfx/render_pass.hpp ${MBGL_ROOT}/src/mbgl/gfx/renderbuffer.hpp ${MBGL_ROOT}/src/mbgl/gfx/renderer_backend.cpp + ${MBGL_ROOT}/src/mbgl/gfx/rendering_stats.cpp ${MBGL_ROOT}/src/mbgl/gfx/stencil_mode.hpp ${MBGL_ROOT}/src/mbgl/gfx/texture.hpp ${MBGL_ROOT}/src/mbgl/gfx/types.hpp @@ -306,6 +308,7 @@ add_library( ${MBGL_ROOT}/src/mbgl/gl/enum.hpp ${MBGL_ROOT}/src/mbgl/gl/extension.hpp ${MBGL_ROOT}/src/mbgl/gl/framebuffer.hpp + ${MBGL_ROOT}/src/mbgl/gl/index_buffer_resource.cpp ${MBGL_ROOT}/src/mbgl/gl/index_buffer_resource.hpp ${MBGL_ROOT}/src/mbgl/gl/object.cpp ${MBGL_ROOT}/src/mbgl/gl/object.hpp @@ -319,6 +322,7 @@ add_library( ${MBGL_ROOT}/src/mbgl/gl/state.hpp ${MBGL_ROOT}/src/mbgl/gl/texture.cpp ${MBGL_ROOT}/src/mbgl/gl/texture.hpp + ${MBGL_ROOT}/src/mbgl/gl/texture_resource.cpp ${MBGL_ROOT}/src/mbgl/gl/texture_resource.hpp ${MBGL_ROOT}/src/mbgl/gl/types.hpp ${MBGL_ROOT}/src/mbgl/gl/uniform.cpp @@ -330,6 +334,7 @@ add_library( ${MBGL_ROOT}/src/mbgl/gl/vertex_array.cpp ${MBGL_ROOT}/src/mbgl/gl/vertex_array.hpp ${MBGL_ROOT}/src/mbgl/gl/vertex_array_extension.hpp + ${MBGL_ROOT}/src/mbgl/gl/vertex_buffer_resource.cpp ${MBGL_ROOT}/src/mbgl/gl/vertex_buffer_resource.hpp ${MBGL_ROOT}/src/mbgl/layermanager/background_layer_factory.cpp ${MBGL_ROOT}/src/mbgl/layermanager/circle_layer_factory.cpp diff --git a/platform/default/src/mbgl/gfx/headless_frontend.cpp b/platform/default/src/mbgl/gfx/headless_frontend.cpp index 87d09911a2..9e819f6653 100644 --- a/platform/default/src/mbgl/gfx/headless_frontend.cpp +++ b/platform/default/src/mbgl/gfx/headless_frontend.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include diff --git a/src/core-files.json b/src/core-files.json index e8795fbdd3..c25e8273d4 100644 --- a/src/core-files.json +++ b/src/core-files.json @@ -17,20 +17,24 @@ "src/mbgl/geometry/line_atlas.cpp", "src/mbgl/gfx/attribute.cpp", "src/mbgl/gfx/renderer_backend.cpp", + "src/mbgl/gfx/rendering_stats.cpp", "src/mbgl/gl/attribute.cpp", "src/mbgl/gl/command_encoder.cpp", "src/mbgl/gl/context.cpp", "src/mbgl/gl/debugging_extension.cpp", "src/mbgl/gl/enum.cpp", + "src/mbgl/gl/index_buffer_resource.cpp", "src/mbgl/gl/object.cpp", "src/mbgl/gl/offscreen_texture.cpp", "src/mbgl/gl/render_pass.cpp", "src/mbgl/gl/renderer_backend.cpp", "src/mbgl/gl/texture.cpp", + "src/mbgl/gl/texture_resource.cpp", "src/mbgl/gl/uniform.cpp", "src/mbgl/gl/upload_pass.cpp", "src/mbgl/gl/value.cpp", "src/mbgl/gl/vertex_array.cpp", + "src/mbgl/gl/vertex_buffer_resource.cpp", "src/mbgl/layermanager/background_layer_factory.cpp", "src/mbgl/layermanager/circle_layer_factory.cpp", "src/mbgl/layermanager/custom_layer_factory.cpp", @@ -331,6 +335,7 @@ "mbgl/gfx/backend_scope.hpp": "include/mbgl/gfx/backend_scope.hpp", "mbgl/gfx/renderable.hpp": "include/mbgl/gfx/renderable.hpp", "mbgl/gfx/renderer_backend.hpp": "include/mbgl/gfx/renderer_backend.hpp", + "mbgl/gfx/rendering_stats.hpp": "include/mbgl/gfx/rendering_stats.hpp", "mbgl/gl/renderable_resource.hpp": "include/mbgl/gl/renderable_resource.hpp", "mbgl/gl/renderer_backend.hpp": "include/mbgl/gl/renderer_backend.hpp", "mbgl/i18n/collator.hpp": "include/mbgl/i18n/collator.hpp", diff --git a/src/mbgl/gfx/context.hpp b/src/mbgl/gfx/context.hpp index 2c7cb14899..fe0851be11 100644 --- a/src/mbgl/gfx/context.hpp +++ b/src/mbgl/gfx/context.hpp @@ -1,12 +1,13 @@ #pragma once #include -#include #include #include #include -#include +#include +#include #include +#include namespace mbgl { @@ -85,6 +86,8 @@ public: public: virtual std::unique_ptr createCommandEncoder() = 0; + virtual const RenderingStats& renderingStats() const = 0; + #if not defined(NDEBUG) public: virtual void visualizeStencilBuffer() = 0; diff --git a/src/mbgl/gfx/rendering_stats.cpp b/src/mbgl/gfx/rendering_stats.cpp new file mode 100644 index 0000000000..0a239ebd11 --- /dev/null +++ b/src/mbgl/gfx/rendering_stats.cpp @@ -0,0 +1,12 @@ +#include + +namespace mbgl { +namespace gfx { + +bool RenderingStats::isZero() const { + return numActiveTextures == 0 && numCreatedTextures == 0 && numBuffers == 0 && numFrameBuffers == 0 && + memTextures == 0 && memIndexBuffers == 0 && memVertexBuffers == 0; +} + +} // namespace gfx +} // namespace mbgl \ No newline at end of file diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index f81ac48ee5..e2bcc7fadc 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -54,13 +54,15 @@ Context::Context(RendererBackend& backend_) GLint value; MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); return value; - }()), backend(backend_) { -} + }()), + backend(backend_), + stats() {} Context::~Context() { if (cleanupOnDestruction) { reset(); } + assert(stats.isZero()); } void Context::initializeExtensions(const std::function& getProcAddress) { @@ -206,10 +208,12 @@ UniqueTexture Context::createUniqueTexture() { if (pooledTextures.empty()) { pooledTextures.resize(TextureMax); MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data())); + stats.numCreatedTextures += TextureMax; } TextureID id = pooledTextures.back(); pooledTextures.pop_back(); + stats.numActiveTextures++; // NOLINTNEXTLINE(performance-move-const-arg) return UniqueTexture{std::move(id), {this}}; } @@ -238,6 +242,7 @@ VertexArray Context::createVertexArray() { UniqueFramebuffer Context::createFramebuffer() { FramebufferID id = 0; MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); + stats.numFrameBuffers++; // NOLINTNEXTLINE(performance-move-const-arg) return UniqueFramebuffer{ std::move(id), { this } }; } @@ -245,8 +250,10 @@ UniqueFramebuffer Context::createFramebuffer() { std::unique_ptr Context::createTextureResource( const Size size, const gfx::TexturePixelType format, const gfx::TextureChannelDataType type) { auto obj = createUniqueTexture(); + int textureByteSize = gl::TextureResource::getStorageSize(size, format, type); + stats.memTextures += textureByteSize; std::unique_ptr resource = - std::make_unique(std::move(obj)); + std::make_unique(std::move(obj), textureByteSize); // Always use texture unit 0 for manipulating it. activeTextureUnit = 0; @@ -517,6 +524,8 @@ void Context::clear(optional color, } MBGL_CHECK_ERROR(glClear(mask)); + + stats.numDrawCalls = 0; } void Context::setCullFaceMode(const gfx::CullFaceMode& mode) { @@ -583,6 +592,14 @@ std::unique_ptr Context::createCommandEncoder() { return std::make_unique(*this); } +gfx::RenderingStats& Context::renderingStats() { + return stats; +} + +const gfx::RenderingStats& Context::renderingStats() const { + return stats; +} + void Context::finish() { MBGL_CHECK_ERROR(glFinish()); } @@ -611,6 +628,8 @@ void Context::draw(const gfx::DrawMode& drawMode, static_cast(indexLength), GL_UNSIGNED_SHORT, reinterpret_cast(sizeof(uint16_t) * indexOffset))); + + stats.numDrawCalls++; } void Context::performCleanup() { @@ -647,6 +666,7 @@ void Context::performCleanup() { } } MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data())); + stats.numBuffers -= int(abandonedBuffers.size()); abandonedBuffers.clear(); } @@ -659,6 +679,8 @@ void Context::performCleanup() { } } MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data())); + stats.numCreatedTextures -= int(abandonedTextures.size()); + assert(stats.numCreatedTextures >= 0); abandonedTextures.clear(); } @@ -682,6 +704,8 @@ void Context::performCleanup() { } MBGL_CHECK_ERROR( glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data())); + stats.numFrameBuffers -= int(abandonedFramebuffers.size()); + assert(stats.numFrameBuffers >= 0); abandonedFramebuffers.clear(); } diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index edcdde1ec6..b0d043ff9f 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -43,6 +43,9 @@ public: std::unique_ptr createCommandEncoder() override; + gfx::RenderingStats& renderingStats(); + const gfx::RenderingStats& renderingStats() const override; + void initializeExtensions(const std::function&); void enableDebugging(); @@ -132,6 +135,7 @@ private: RendererBackend& backend; bool cleanupOnDestruction = true; + gfx::RenderingStats stats; std::unique_ptr debugging; std::unique_ptr vertexArray; diff --git a/src/mbgl/gl/index_buffer_resource.cpp b/src/mbgl/gl/index_buffer_resource.cpp new file mode 100644 index 0000000000..2ef178846b --- /dev/null +++ b/src/mbgl/gl/index_buffer_resource.cpp @@ -0,0 +1,14 @@ +#include +#include + +namespace mbgl { +namespace gl { + +IndexBufferResource::~IndexBufferResource() { + auto& stats = buffer.get_deleter().context.renderingStats(); + stats.memIndexBuffers -= byteSize; + assert(stats.memIndexBuffers >= 0); +} + +} // namespace gl +} // namespace mbgl \ No newline at end of file diff --git a/src/mbgl/gl/index_buffer_resource.hpp b/src/mbgl/gl/index_buffer_resource.hpp index 2da25fdb96..00c66be5b5 100644 --- a/src/mbgl/gl/index_buffer_resource.hpp +++ b/src/mbgl/gl/index_buffer_resource.hpp @@ -8,10 +8,11 @@ namespace gl { class IndexBufferResource : public gfx::IndexBufferResource { public: - IndexBufferResource(UniqueBuffer&& buffer_) : buffer(std::move(buffer_)) { - } + IndexBufferResource(UniqueBuffer&& buffer_, int byteSize_) : buffer(std::move(buffer_)), byteSize(byteSize_) {} + ~IndexBufferResource(); UniqueBuffer buffer; + int byteSize; }; } // namespace gl diff --git a/src/mbgl/gl/object.cpp b/src/mbgl/gl/object.cpp index ec2998a27d..c075aa8f13 100644 --- a/src/mbgl/gl/object.cpp +++ b/src/mbgl/gl/object.cpp @@ -28,6 +28,8 @@ void TextureDeleter::operator()(TextureID id) const { } else { context->pooledTextures.push_back(id); } + context->renderingStats().numActiveTextures--; + assert(context->renderingStats().numActiveTextures >= 0); } void VertexArrayDeleter::operator()(VertexArrayID id) const { diff --git a/src/mbgl/gl/texture_resource.cpp b/src/mbgl/gl/texture_resource.cpp new file mode 100644 index 0000000000..b9bf620eea --- /dev/null +++ b/src/mbgl/gl/texture_resource.cpp @@ -0,0 +1,45 @@ +#include +#include + +namespace mbgl { +namespace gl { + +static int channelCount(gfx::TexturePixelType format) { + switch (format) { + case gfx::TexturePixelType::Alpha: + case gfx::TexturePixelType::Depth: + case gfx::TexturePixelType::Luminance: + case gfx::TexturePixelType::Stencil: + return 1; + case gfx::TexturePixelType::RGBA: + return 4; + default: + assert(!"Unknown texture pixel type"); + return 0; + } +} + +static int channelStorageSize(gfx::TextureChannelDataType type) { + switch (type) { + case gfx::TextureChannelDataType::HalfFloat: + return 2; + case gfx::TextureChannelDataType::UnsignedByte: + return 1; + default: + assert(!"Unknown texture channel data type"); + return 0; + } +} + +TextureResource::~TextureResource() { + auto& stats = texture.get_deleter().context->renderingStats(); + stats.memTextures -= byteSize; + assert(stats.memTextures >= 0); +} + +int TextureResource::getStorageSize(const Size& size, gfx::TexturePixelType format, gfx::TextureChannelDataType type) { + return size.width * size.height * channelCount(format) * channelStorageSize(type); +} + +} // namespace gl +} // namespace mbgl \ No newline at end of file diff --git a/src/mbgl/gl/texture_resource.hpp b/src/mbgl/gl/texture_resource.hpp index ed742e75b7..494e5ae8a3 100644 --- a/src/mbgl/gl/texture_resource.hpp +++ b/src/mbgl/gl/texture_resource.hpp @@ -8,14 +8,17 @@ namespace gl { class TextureResource : public gfx::TextureResource { public: - TextureResource(UniqueTexture&& texture_) : texture(std::move(texture_)) { - } + TextureResource(UniqueTexture&& texture_, int byteSize_) : texture(std::move(texture_)), byteSize(byteSize_) {} + ~TextureResource(); + + static int getStorageSize(const Size& size, gfx::TexturePixelType format, gfx::TextureChannelDataType type); UniqueTexture texture; gfx::TextureFilterType filter = gfx::TextureFilterType::Nearest; gfx::TextureMipMapType mipmap = gfx::TextureMipMapType::No; gfx::TextureWrapType wrapX = gfx::TextureWrapType::Clamp; gfx::TextureWrapType wrapY = gfx::TextureWrapType::Clamp; + int byteSize; }; } // namespace gl diff --git a/src/mbgl/gl/upload_pass.cpp b/src/mbgl/gl/upload_pass.cpp index 4312488fb4..962bc72239 100644 --- a/src/mbgl/gl/upload_pass.cpp +++ b/src/mbgl/gl/upload_pass.cpp @@ -20,12 +20,14 @@ std::unique_ptr UploadPass::createVertexBufferResourc const void* data, std::size_t size, const gfx::BufferUsageType usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); + commandEncoder.context.renderingStats().numBuffers++; + commandEncoder.context.renderingStats().memVertexBuffers += size; // NOLINTNEXTLINE(performance-move-const-arg) UniqueBuffer result{ std::move(id), { commandEncoder.context } }; commandEncoder.context.vertexBuffer = result; MBGL_CHECK_ERROR( glBufferData(GL_ARRAY_BUFFER, size, data, Enum::to(usage))); - return std::make_unique(std::move(result)); + return std::make_unique(std::move(result), size); } void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, @@ -39,13 +41,15 @@ std::unique_ptr UploadPass::createIndexBufferResource( const void* data, std::size_t size, const gfx::BufferUsageType usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); + commandEncoder.context.renderingStats().numBuffers++; + commandEncoder.context.renderingStats().memIndexBuffers += size; // NOLINTNEXTLINE(performance-move-const-arg) UniqueBuffer result{ std::move(id), { commandEncoder.context } }; commandEncoder.context.bindVertexArray = 0; commandEncoder.context.globalVertexArrayState.indexBuffer = result; MBGL_CHECK_ERROR( glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, Enum::to(usage))); - return std::make_unique(std::move(result)); + return std::make_unique(std::move(result), size); } void UploadPass::updateIndexBufferResource(gfx::IndexBufferResource& resource, @@ -65,8 +69,10 @@ UploadPass::createTextureResource(const Size size, gfx::TexturePixelType format, gfx::TextureChannelDataType type) { auto obj = commandEncoder.context.createUniqueTexture(); + int textureByteSize = gl::TextureResource::getStorageSize(size, format, type); + commandEncoder.context.renderingStats().memTextures += textureByteSize; std::unique_ptr resource = - std::make_unique(std::move(obj)); + std::make_unique(std::move(obj), textureByteSize); commandEncoder.context.pixelStoreUnpack = { 1 }; updateTextureResource(*resource, size, data, format, type); // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. diff --git a/src/mbgl/gl/vertex_buffer_resource.cpp b/src/mbgl/gl/vertex_buffer_resource.cpp new file mode 100644 index 0000000000..cddbdd43d0 --- /dev/null +++ b/src/mbgl/gl/vertex_buffer_resource.cpp @@ -0,0 +1,14 @@ +#include +#include + +namespace mbgl { +namespace gl { + +VertexBufferResource::~VertexBufferResource() { + auto& stats = buffer.get_deleter().context.renderingStats(); + stats.memVertexBuffers -= byteSize; + assert(stats.memVertexBuffers >= 0); +} + +} // namespace gl +} // namespace mbgl \ No newline at end of file diff --git a/src/mbgl/gl/vertex_buffer_resource.hpp b/src/mbgl/gl/vertex_buffer_resource.hpp index 95e5e75d45..f9c599c757 100644 --- a/src/mbgl/gl/vertex_buffer_resource.hpp +++ b/src/mbgl/gl/vertex_buffer_resource.hpp @@ -8,10 +8,11 @@ namespace gl { class VertexBufferResource : public gfx::VertexBufferResource { public: - VertexBufferResource(UniqueBuffer&& buffer_) : buffer(std::move(buffer_)) { - } + VertexBufferResource(UniqueBuffer&& buffer_, int byteSize_) : buffer(std::move(buffer_)), byteSize(byteSize_) {} + ~VertexBufferResource(); UniqueBuffer buffer; + int byteSize; }; } // namespace gl -- cgit v1.2.1 From a7a7e8cbe29e672d020db1d150e887f33d584a2d Mon Sep 17 00:00:00 2001 From: Mikko Pulkki Date: Tue, 15 Oct 2019 12:03:04 +0300 Subject: [render-test] Implement gfx probe for tracking gpu resources --- bin/render.cpp | 2 +- .../default/include/mbgl/gfx/headless_frontend.hpp | 8 +- .../default/src/mbgl/gfx/headless_frontend.cpp | 11 +- render-test/metadata.hpp | 31 ++++- render-test/parser.cpp | 64 +++++++++ render-test/runner.cpp | 145 ++++++++++++++++++++- render-test/runner.hpp | 3 +- test/api/annotations.test.cpp | 3 +- test/api/custom_geometry_source.test.cpp | 2 +- test/api/custom_layer.test.cpp | 2 +- test/api/recycle_map.cpp | 4 +- test/gl/context.test.cpp | 2 +- test/map/map.test.cpp | 20 +-- test/text/local_glyph_rasterizer.test.cpp | 4 +- 14 files changed, 267 insertions(+), 34 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index 85231c8cba..409dfa7922 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -99,7 +99,7 @@ int main(int argc, char *argv[]) { try { std::ofstream out(output, std::ios::binary); - out << encodePNG(frontend.render(map)); + out << encodePNG(frontend.render(map).image); out.close(); } catch(std::exception& e) { std::cout << "Error: " << e.what() << std::endl; diff --git a/platform/default/include/mbgl/gfx/headless_frontend.hpp b/platform/default/include/mbgl/gfx/headless_frontend.hpp index 353452123d..8a98b4112d 100644 --- a/platform/default/include/mbgl/gfx/headless_frontend.hpp +++ b/platform/default/include/mbgl/gfx/headless_frontend.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -17,6 +18,11 @@ class TransformState; class HeadlessFrontend : public RendererFrontend { public: + struct RenderResult { + PremultipliedImage image; + gfx::RenderingStats stats; + }; + HeadlessFrontend(float pixelRatio_, gfx::HeadlessBackend::SwapBehaviour swapBehviour = gfx::HeadlessBackend::SwapBehaviour::NoFlush, gfx::ContextMode mode = gfx::ContextMode::Unique, @@ -48,7 +54,7 @@ public: LatLng latLngForPixel(const ScreenCoordinate&); PremultipliedImage readStillImage(); - PremultipliedImage render(Map&); + RenderResult render(Map&); void renderOnce(Map&); optional getTransformState() const; diff --git a/platform/default/src/mbgl/gfx/headless_frontend.cpp b/platform/default/src/mbgl/gfx/headless_frontend.cpp index 9e819f6653..5235b2f408 100644 --- a/platform/default/src/mbgl/gfx/headless_frontend.cpp +++ b/platform/default/src/mbgl/gfx/headless_frontend.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include @@ -140,19 +140,20 @@ PremultipliedImage HeadlessFrontend::readStillImage() { return backend->readStillImage(); } -PremultipliedImage HeadlessFrontend::render(Map& map) { - PremultipliedImage result; +HeadlessFrontend::RenderResult HeadlessFrontend::render(Map& map) { + HeadlessFrontend::RenderResult result; std::exception_ptr error; map.renderStill([&](std::exception_ptr e) { if (e) { error = e; } else { - result = backend->readStillImage(); + result.image = backend->readStillImage(); + result.stats = getBackend()->getContext().renderingStats(); } }); - while (!result.valid() && !error) { + while (!result.image.valid() && !error) { util::RunLoop::Get()->runOnce(); } diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp index 996a2bc429..567c89e3fc 100644 --- a/render-test/metadata.hpp +++ b/render-test/metadata.hpp @@ -11,6 +11,12 @@ #include +namespace mbgl { +namespace gfx { +struct RenderingStats; +} +} // namespace mbgl + struct TestStatistics { TestStatistics() = default; @@ -82,13 +88,36 @@ struct NetworkProbe { size_t transferred; }; +struct GfxProbe { + struct Memory { + Memory() = default; + Memory(int allocated_, int peak_) : allocated(allocated_), peak(peak_) {} + + int allocated; + int peak; + }; + + GfxProbe() = default; + GfxProbe(const mbgl::gfx::RenderingStats&, const GfxProbe&); + + int numDrawCalls; + int numTextures; + int numBuffers; + int numFrameBuffers; + + Memory memTextures; + Memory memIndexBuffers; + Memory memVertexBuffers; +}; + class TestMetrics { public: - bool isEmpty() const { return fileSize.empty() && memory.empty() && network.empty() && fps.empty(); } + bool isEmpty() const { return fileSize.empty() && memory.empty() && network.empty() && fps.empty() && gfx.empty(); } std::map fileSize; std::map memory; std::map network; std::map fps; + std::map gfx; }; struct TestMetadata { diff --git a/render-test/parser.cpp b/render-test/parser.cpp index 5a91fc7a58..b5d48d23a1 100644 --- a/render-test/parser.cpp +++ b/render-test/parser.cpp @@ -238,6 +238,36 @@ std::string serializeMetrics(const TestMetrics& metrics) { // End fps section } + if (!metrics.gfx.empty()) { + // Start gfx section + writer.Key("gfx"); + writer.StartArray(); + for (const auto& gfxProbe : metrics.gfx) { + assert(!gfxProbe.first.empty()); + writer.StartArray(); + writer.String(gfxProbe.first.c_str()); + writer.Int(gfxProbe.second.numDrawCalls); + writer.Int(gfxProbe.second.numTextures); + writer.Int(gfxProbe.second.numBuffers); + writer.Int(gfxProbe.second.numFrameBuffers); + writer.StartArray(); + writer.Int(gfxProbe.second.memTextures.allocated); + writer.Int(gfxProbe.second.memTextures.peak); + writer.EndArray(); + writer.StartArray(); + writer.Int(gfxProbe.second.memIndexBuffers.allocated); + writer.Int(gfxProbe.second.memIndexBuffers.peak); + writer.EndArray(); + writer.StartArray(); + writer.Int(gfxProbe.second.memVertexBuffers.allocated); + writer.Int(gfxProbe.second.memVertexBuffers.peak); + writer.EndArray(); + writer.EndArray(); + } + writer.EndArray(); + // End gfx section + } + writer.EndObject(); return s.GetString(); @@ -354,6 +384,40 @@ TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) { } } + if (document.HasMember("gfx")) { + const mbgl::JSValue& gfxValue = document["gfx"]; + assert(gfxValue.IsArray()); + for (auto& probeValue : gfxValue.GetArray()) { + assert(probeValue.IsArray()); + assert(probeValue.Size() >= 8u); + assert(probeValue[0].IsString()); + assert(probeValue[1].IsInt()); + assert(probeValue[2].IsInt()); + assert(probeValue[3].IsInt()); + assert(probeValue[4].IsInt()); + assert(probeValue[5].IsArray()); + assert(probeValue[6].IsArray()); + assert(probeValue[7].IsArray()); + + const std::string mark{probeValue[0].GetString(), probeValue[0].GetStringLength()}; + assert(!mark.empty()); + + GfxProbe probe; + probe.numDrawCalls = probeValue[1].GetInt(); + probe.numTextures = probeValue[2].GetInt(); + probe.numBuffers = probeValue[3].GetInt(); + probe.numFrameBuffers = probeValue[4].GetInt(); + probe.memTextures.allocated = probeValue[5].GetArray()[0].GetInt(); + probe.memTextures.peak = probeValue[5].GetArray()[1].GetInt(); + probe.memIndexBuffers.allocated = probeValue[6].GetArray()[0].GetInt(); + probe.memIndexBuffers.peak = probeValue[6].GetArray()[1].GetInt(); + probe.memVertexBuffers.allocated = probeValue[7].GetArray()[0].GetInt(); + probe.memVertexBuffers.peak = probeValue[7].GetArray()[1].GetInt(); + + result.gfx.insert({mark, std::move(probe)}); + } + } + return result; } diff --git a/render-test/runner.cpp b/render-test/runner.cpp index e882e394be..8a4b0b3b0e 100644 --- a/render-test/runner.cpp +++ b/render-test/runner.cpp @@ -34,6 +34,23 @@ using namespace mbgl; +GfxProbe::GfxProbe(const mbgl::gfx::RenderingStats& stats, const GfxProbe& prev) + : numBuffers(stats.numBuffers), + numDrawCalls(stats.numDrawCalls), + numFrameBuffers(stats.numFrameBuffers), + numTextures(stats.numActiveTextures), + memIndexBuffers(stats.memIndexBuffers, std::max(stats.memIndexBuffers, prev.memIndexBuffers.peak)), + memVertexBuffers(stats.memVertexBuffers, std::max(stats.memVertexBuffers, prev.memVertexBuffers.peak)), + memTextures(stats.memTextures, std::max(stats.memTextures, prev.memTextures.peak)) {} + +struct RunContext { + RunContext() = default; + + GfxProbe activeGfxProbe; + GfxProbe baselineGfxProbe; + bool gfxProbeActive; +}; + class TestRunnerMapObserver : public MapObserver { public: TestRunnerMapObserver() : mapLoadFailure(false), finishRenderingMap(false), idle(false) {} @@ -391,10 +408,91 @@ bool TestRunner::checkRenderTestResults(mbgl::PremultipliedImage&& actualImage, return false; } } + // Check gfx metrics + for (const auto& expected : metadata.expectedMetrics.gfx) { + auto actual = metadata.metrics.gfx.find(expected.first); + if (actual == metadata.metrics.gfx.end()) { + metadata.errorMessage = "Failed to find gfx probe: " + expected.first; + return false; + } + + const auto& probeName = expected.first; + const auto& expectedValue = expected.second; + const auto& actualValue = actual->second; + bool failed = false; + + if (expectedValue.numDrawCalls != actualValue.numDrawCalls) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Number of draw calls at probe\"" << probeName << "\" is " << actualValue.numDrawCalls + << ", expected is " << expectedValue.numDrawCalls; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (expectedValue.numTextures != actualValue.numTextures) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Number of textures at probe \"" << probeName << "\" is " << actualValue.numTextures + << ", expected is " << expectedValue.numTextures; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (expectedValue.numBuffers != actualValue.numBuffers) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Number of vertex and index buffers at probe \"" << probeName << "\" is " << actualValue.numBuffers + << ", expected is " << expectedValue.numBuffers; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (expectedValue.numFrameBuffers != actualValue.numFrameBuffers) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Number of frame buffers at probe \"" << probeName << "\" is " << actualValue.numFrameBuffers + << ", expected is " << expectedValue.numFrameBuffers; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (expectedValue.memTextures.peak != actualValue.memTextures.peak) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Allocated texture memory peak size at probe \"" << probeName << "\" is " + << actualValue.memTextures.peak << " bytes, expected is " << expectedValue.memTextures.peak << " bytes"; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (expectedValue.memIndexBuffers.peak != actualValue.memIndexBuffers.peak) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Allocated index buffer memory peak size at probe \"" << probeName << "\" is " + << actualValue.memIndexBuffers.peak << " bytes, expected is " << expectedValue.memIndexBuffers.peak + << " bytes"; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (expectedValue.memVertexBuffers.peak != actualValue.memVertexBuffers.peak) { + std::stringstream ss; + if (!metadata.errorMessage.empty()) ss << std::endl; + ss << "Allocated vertex buffer memory peak size at probe \"" << probeName << "\" is " + << actualValue.memVertexBuffers.peak << " bytes, expected is " << expectedValue.memVertexBuffers.peak + << " bytes"; + metadata.errorMessage += ss.str(); + failed = true; + } + + if (failed) return false; + } + return true; } -bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { +bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata, RunContext& ctx) { if (!metadata.document.HasMember("metadata") || !metadata.document["metadata"].HasMember("test") || !metadata.document["metadata"]["test"].HasMember("operations")) { return true; @@ -446,6 +544,9 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { static const std::string getFeatureStateOp("getFeatureState"); static const std::string removeFeatureStateOp("removeFeatureState"); static const std::string panGestureOp("panGesture"); + static const std::string gfxProbeOp("probeGFX"); + static const std::string gfxProbeStartOp("probeGFXStart"); + static const std::string gfxProbeEndOp("probeGFXEnd"); if (operationArray[0].GetString() == waitOp) { // wait @@ -955,13 +1056,47 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) { metadata.metrics.fps.insert({std::move(mark), {averageFps, minOnePcFps, 0.0f}}); + } else if (operationArray[0].GetString() == gfxProbeStartOp) { + // probeGFXStart + assert(!ctx.gfxProbeActive); + ctx.gfxProbeActive = true; + ctx.baselineGfxProbe = ctx.activeGfxProbe; + } else if (operationArray[0].GetString() == gfxProbeEndOp) { + // probeGFXEnd + assert(ctx.gfxProbeActive); + ctx.gfxProbeActive = false; + } else if (operationArray[0].GetString() == gfxProbeOp) { + // probeGFX + assert(operationArray.Size() >= 2u); + assert(operationArray[1].IsString()); + + std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength()); + + // Render the map and fetch rendering stats + gfx::RenderingStats stats; + + try { + stats = frontend.render(map).stats; + } catch (const std::exception&) { + return false; + } + + ctx.activeGfxProbe = GfxProbe(stats, ctx.activeGfxProbe); + + // Compare memory allocations to the baseline probe + GfxProbe metricProbe = ctx.activeGfxProbe; + metricProbe.memIndexBuffers.peak -= ctx.baselineGfxProbe.memIndexBuffers.peak; + metricProbe.memVertexBuffers.peak -= ctx.baselineGfxProbe.memVertexBuffers.peak; + metricProbe.memTextures.peak -= ctx.baselineGfxProbe.memTextures.peak; + metadata.metrics.gfx.insert({mark, metricProbe}); + } else { metadata.errorMessage = std::string("Unsupported operation: ") + operationArray[0].GetString(); return false; } operationsArray.Erase(operationIt); - return runOperations(key, metadata); + return runOperations(key, metadata, ctx); } TestRunner::Impl::Impl(const TestMetadata& metadata) @@ -1002,13 +1137,15 @@ bool TestRunner::run(TestMetadata& metadata) { map.getStyle().loadJSON(serializeJsonValue(metadata.document)); map.jumpTo(map.getStyle().getDefaultCamera()); - if (!runOperations(key, metadata)) { + RunContext ctx{}; + + if (!runOperations(key, metadata, ctx)) { return false; } mbgl::PremultipliedImage image; try { - if (metadata.outputsImage) image = frontend.render(map); + if (metadata.outputsImage) image = frontend.render(map).image; } catch (const std::exception&) { return false; } diff --git a/render-test/runner.hpp b/render-test/runner.hpp index bc97f8300b..4f80286c0b 100644 --- a/render-test/runner.hpp +++ b/render-test/runner.hpp @@ -8,6 +8,7 @@ #include #include +struct RunContext; class TestRunnerMapObserver; struct TestMetadata; @@ -22,7 +23,7 @@ public: void doShuffle(uint32_t seed); private: - bool runOperations(const std::string& key, TestMetadata&); + bool runOperations(const std::string& key, TestMetadata&, RunContext&); bool checkQueryTestResults(mbgl::PremultipliedImage&& actualImage, std::vector&& features, TestMetadata&); diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index 03330dc4c6..4886d90a93 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -33,8 +33,7 @@ public: MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())}; void checkRendering(const char * name) { - test::checkImage(std::string("test/fixtures/annotations/") + name, - frontend.render(map), 0.0002, 0.1); + test::checkImage(std::string("test/fixtures/annotations/") + name, frontend.render(map).image, 0.0002, 0.1); } }; diff --git a/test/api/custom_geometry_source.test.cpp b/test/api/custom_geometry_source.test.cpp index f35b4d335c..93cf6ba56e 100644 --- a/test/api/custom_geometry_source.test.cpp +++ b/test/api/custom_geometry_source.test.cpp @@ -64,5 +64,5 @@ TEST(CustomGeometrySource, Grid) { layer->setLineColor(Color{ 1.0, 1.0, 1.0, 1.0 }); map.getStyle().addLayer(std::move(layer)); - test::checkImage("test/fixtures/custom_geometry_source/grid", frontend.render(map), 0.0006, 0.1); + test::checkImage("test/fixtures/custom_geometry_source/grid", frontend.render(map).image, 0.0006, 0.1); } diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp index 175d053f93..2222645147 100644 --- a/test/api/custom_layer.test.cpp +++ b/test/api/custom_layer.test.cpp @@ -108,5 +108,5 @@ TEST(CustomLayer, Basic) { layer->setFillColor(Color{ 1.0, 1.0, 0.0, 1.0 }); map.getStyle().addLayer(std::move(layer)); - test::checkImage("test/fixtures/custom_layer/basic", frontend.render(map), 0.0006, 0.1); + test::checkImage("test/fixtures/custom_layer/basic", frontend.render(map).image, 0.0006, 0.1); } diff --git a/test/api/recycle_map.cpp b/test/api/recycle_map.cpp index b3c573b1a2..be7bb77b4c 100644 --- a/test/api/recycle_map.cpp +++ b/test/api/recycle_map.cpp @@ -45,10 +45,10 @@ TEST(API, RecycleMapUpdateImages) { // default marker loadStyle("default_marker", "test/fixtures/sprites/default_marker.png"); - test::checkImage("test/fixtures/recycle_map/default_marker", frontend.render(*map), 0.0006, 0.1); + test::checkImage("test/fixtures/recycle_map/default_marker", frontend.render(*map).image, 0.0006, 0.1); // flipped marker loadStyle("flipped_marker", "test/fixtures/sprites/flipped_marker.png"); - test::checkImage("test/fixtures/recycle_map/flipped_marker", frontend.render(*map), 0.0006, 0.1); + test::checkImage("test/fixtures/recycle_map/flipped_marker", frontend.render(*map).image, 0.0006, 0.1); } diff --git a/test/gl/context.test.cpp b/test/gl/context.test.cpp index 5c42eb9344..9c709b7597 100644 --- a/test/gl/context.test.cpp +++ b/test/gl/context.test.cpp @@ -119,5 +119,5 @@ TEST(GLContextMode, Shared) { MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3)); } - test::checkImage("test/fixtures/shared_context", frontend.render(map), 0.5, 0.1); + test::checkImage("test/fixtures/shared_context", frontend.render(map).image, 0.5, 0.1); } diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 6f4b14a681..0eebc93f32 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -259,10 +259,7 @@ TEST(Map, Offline) { test.map.getStyle().loadURL(prefix + "style.json"); - test::checkImage("test/fixtures/map/offline", - test.frontend.render(test.map), - 0.0015, - 0.1); + test::checkImage("test/fixtures/map/offline", test.frontend.render(test.map).image, 0.0015, 0.1); NetworkStatus::Set(NetworkStatus::Status::Online); } @@ -608,7 +605,7 @@ TEST(Map, AddLayer) { layer->setBackgroundColor({ { 1, 0, 0, 1 } }); test.map.getStyle().addLayer(std::move(layer)); - test::checkImage("test/fixtures/map/add_layer", test.frontend.render(test.map)); + test::checkImage("test/fixtures/map/add_layer", test.frontend.render(test.map).image); } TEST(Map, WithoutVAOExtension) { @@ -623,7 +620,7 @@ TEST(Map, WithoutVAOExtension) { test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/water.json")); - test::checkImage("test/fixtures/map/no_vao", test.frontend.render(test.map), 0.002); + test::checkImage("test/fixtures/map/no_vao", test.frontend.render(test.map).image, 0.002); } TEST(Map, RemoveLayer) { @@ -636,7 +633,7 @@ TEST(Map, RemoveLayer) { test.map.getStyle().addLayer(std::move(layer)); test.map.getStyle().removeLayer("background"); - test::checkImage("test/fixtures/map/remove_layer", test.frontend.render(test.map)); + test::checkImage("test/fixtures/map/remove_layer", test.frontend.render(test.map).image); } TEST(Map, DisabledSources) { @@ -694,9 +691,9 @@ TEST(Map, DisabledSources) { } )STYLE"); - test::checkImage("test/fixtures/map/disabled_layers/first", test.frontend.render(test.map)); + test::checkImage("test/fixtures/map/disabled_layers/first", test.frontend.render(test.map).image); test.map.jumpTo(CameraOptions().withZoom(0.5)); - test::checkImage("test/fixtures/map/disabled_layers/second", test.frontend.render(test.map)); + test::checkImage("test/fixtures/map/disabled_layers/second", test.frontend.render(test.map).image); } TEST(Map, DontLoadUnneededTiles) { @@ -815,10 +812,7 @@ TEST(Map, NoContentTiles) { }] })STYLE"); - test::checkImage("test/fixtures/map/nocontent", - test.frontend.render(test.map), - 0.0015, - 0.1); + test::checkImage("test/fixtures/map/nocontent", test.frontend.render(test.map).image, 0.0015, 0.1); } // https://github.com/mapbox/mapbox-gl-native/issues/12432 diff --git a/test/text/local_glyph_rasterizer.test.cpp b/test/text/local_glyph_rasterizer.test.cpp index 94c37b170b..d109b28f32 100644 --- a/test/text/local_glyph_rasterizer.test.cpp +++ b/test/text/local_glyph_rasterizer.test.cpp @@ -43,7 +43,9 @@ public: void checkRendering(const char * name, double imageMatchPixelsThreshold = 0.015, double pixelMatchThreshold = 0.1) { test::checkImage(std::string("test/fixtures/local_glyphs/") + name, - frontend.render(map), imageMatchPixelsThreshold, pixelMatchThreshold); + frontend.render(map).image, + imageMatchPixelsThreshold, + pixelMatchThreshold); } }; -- cgit v1.2.1 From 6900ac9837c6981b2a3f8d389ac09c0fca56b749 Mon Sep 17 00:00:00 2001 From: Mikko Pulkki Date: Wed, 23 Oct 2019 20:53:19 +0300 Subject: [render-test] Add gfx probe test cases --- .../tests/gfx/fail-ib-mem-mismatch/expected.png | Bin 0 -> 46431 bytes .../tests/gfx/fail-ib-mem-mismatch/metrics.json | 5 +++++ .../tests/gfx/fail-ib-mem-mismatch/style.json | 20 +++++++++++++++++ .../fail-negative-framebuffer-count/expected.png | Bin 0 -> 46431 bytes .../fail-negative-framebuffer-count/metrics.json | 5 +++++ .../gfx/fail-negative-framebuffer-count/style.json | 20 +++++++++++++++++ .../gfx/fail-texture-mem-mismatch/expected.png | Bin 0 -> 46431 bytes .../gfx/fail-texture-mem-mismatch/metrics.json | 5 +++++ .../tests/gfx/fail-texture-mem-mismatch/style.json | 20 +++++++++++++++++ .../tests/gfx/fail-too-few-buffers/expected.png | Bin 0 -> 46431 bytes .../tests/gfx/fail-too-few-buffers/metrics.json | 5 +++++ .../tests/gfx/fail-too-few-buffers/style.json | 20 +++++++++++++++++ .../tests/gfx/fail-too-few-textures/expected.png | Bin 0 -> 46431 bytes .../tests/gfx/fail-too-few-textures/metrics.json | 5 +++++ .../tests/gfx/fail-too-few-textures/style.json | 20 +++++++++++++++++ .../tests/gfx/fail-too-many-drawcalls/expected.png | Bin 0 -> 46431 bytes .../tests/gfx/fail-too-many-drawcalls/metrics.json | 5 +++++ .../tests/gfx/fail-too-many-drawcalls/style.json | 20 +++++++++++++++++ .../tests/gfx/fail-vb-mem-mismatch/expected.png | Bin 0 -> 46431 bytes .../tests/gfx/fail-vb-mem-mismatch/metrics.json | 5 +++++ .../tests/gfx/fail-vb-mem-mismatch/style.json | 20 +++++++++++++++++ .../tests/gfx/pass-double-probe/expected.png | Bin 0 -> 42373 bytes .../tests/gfx/pass-double-probe/metrics.json | 6 ++++++ render-test/tests/gfx/pass-double-probe/style.json | 22 +++++++++++++++++++ .../tests/gfx/pass-probe-reset/expected.png | Bin 0 -> 42373 bytes .../tests/gfx/pass-probe-reset/metrics.json | 6 ++++++ render-test/tests/gfx/pass-probe-reset/style.json | 24 +++++++++++++++++++++ render-test/tests/gfx/pass/expected.png | Bin 0 -> 46431 bytes render-test/tests/gfx/pass/metrics.json | 5 +++++ render-test/tests/gfx/pass/style.json | 20 +++++++++++++++++ render-test/tests/should-fail.json | 9 +++++++- 31 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 render-test/tests/gfx/fail-ib-mem-mismatch/expected.png create mode 100644 render-test/tests/gfx/fail-ib-mem-mismatch/metrics.json create mode 100644 render-test/tests/gfx/fail-ib-mem-mismatch/style.json create mode 100644 render-test/tests/gfx/fail-negative-framebuffer-count/expected.png create mode 100644 render-test/tests/gfx/fail-negative-framebuffer-count/metrics.json create mode 100644 render-test/tests/gfx/fail-negative-framebuffer-count/style.json create mode 100644 render-test/tests/gfx/fail-texture-mem-mismatch/expected.png create mode 100644 render-test/tests/gfx/fail-texture-mem-mismatch/metrics.json create mode 100644 render-test/tests/gfx/fail-texture-mem-mismatch/style.json create mode 100644 render-test/tests/gfx/fail-too-few-buffers/expected.png create mode 100644 render-test/tests/gfx/fail-too-few-buffers/metrics.json create mode 100644 render-test/tests/gfx/fail-too-few-buffers/style.json create mode 100644 render-test/tests/gfx/fail-too-few-textures/expected.png create mode 100644 render-test/tests/gfx/fail-too-few-textures/metrics.json create mode 100644 render-test/tests/gfx/fail-too-few-textures/style.json create mode 100644 render-test/tests/gfx/fail-too-many-drawcalls/expected.png create mode 100644 render-test/tests/gfx/fail-too-many-drawcalls/metrics.json create mode 100644 render-test/tests/gfx/fail-too-many-drawcalls/style.json create mode 100644 render-test/tests/gfx/fail-vb-mem-mismatch/expected.png create mode 100644 render-test/tests/gfx/fail-vb-mem-mismatch/metrics.json create mode 100644 render-test/tests/gfx/fail-vb-mem-mismatch/style.json create mode 100644 render-test/tests/gfx/pass-double-probe/expected.png create mode 100644 render-test/tests/gfx/pass-double-probe/metrics.json create mode 100644 render-test/tests/gfx/pass-double-probe/style.json create mode 100644 render-test/tests/gfx/pass-probe-reset/expected.png create mode 100644 render-test/tests/gfx/pass-probe-reset/metrics.json create mode 100644 render-test/tests/gfx/pass-probe-reset/style.json create mode 100644 render-test/tests/gfx/pass/expected.png create mode 100644 render-test/tests/gfx/pass/metrics.json create mode 100644 render-test/tests/gfx/pass/style.json diff --git a/render-test/tests/gfx/fail-ib-mem-mismatch/expected.png b/render-test/tests/gfx/fail-ib-mem-mismatch/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-ib-mem-mismatch/expected.png differ diff --git a/render-test/tests/gfx/fail-ib-mem-mismatch/metrics.json b/render-test/tests/gfx/fail-ib-mem-mismatch/metrics.json new file mode 100644 index 0000000000..2b5c9c3eda --- /dev/null +++ b/render-test/tests/gfx/fail-ib-mem-mismatch/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 14, 63, 1, [371208, 371208], [68598, 65536], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/fail-ib-mem-mismatch/style.json b/render-test/tests/gfx/fail-ib-mem-mismatch/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-ib-mem-mismatch/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/fail-negative-framebuffer-count/expected.png b/render-test/tests/gfx/fail-negative-framebuffer-count/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-negative-framebuffer-count/expected.png differ diff --git a/render-test/tests/gfx/fail-negative-framebuffer-count/metrics.json b/render-test/tests/gfx/fail-negative-framebuffer-count/metrics.json new file mode 100644 index 0000000000..e92cffa571 --- /dev/null +++ b/render-test/tests/gfx/fail-negative-framebuffer-count/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 14, 63, -1, [371208, 371208], [68598, 68598], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/fail-negative-framebuffer-count/style.json b/render-test/tests/gfx/fail-negative-framebuffer-count/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-negative-framebuffer-count/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/fail-texture-mem-mismatch/expected.png b/render-test/tests/gfx/fail-texture-mem-mismatch/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-texture-mem-mismatch/expected.png differ diff --git a/render-test/tests/gfx/fail-texture-mem-mismatch/metrics.json b/render-test/tests/gfx/fail-texture-mem-mismatch/metrics.json new file mode 100644 index 0000000000..fc6f55025f --- /dev/null +++ b/render-test/tests/gfx/fail-texture-mem-mismatch/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 14, 63, 1, [371208, 370000], [68598, 68598], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/fail-texture-mem-mismatch/style.json b/render-test/tests/gfx/fail-texture-mem-mismatch/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-texture-mem-mismatch/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/fail-too-few-buffers/expected.png b/render-test/tests/gfx/fail-too-few-buffers/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-too-few-buffers/expected.png differ diff --git a/render-test/tests/gfx/fail-too-few-buffers/metrics.json b/render-test/tests/gfx/fail-too-few-buffers/metrics.json new file mode 100644 index 0000000000..07b59adeed --- /dev/null +++ b/render-test/tests/gfx/fail-too-few-buffers/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 14, 1000, 1, [371208, 371208], [68598, 68598], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/fail-too-few-buffers/style.json b/render-test/tests/gfx/fail-too-few-buffers/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-too-few-buffers/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/fail-too-few-textures/expected.png b/render-test/tests/gfx/fail-too-few-textures/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-too-few-textures/expected.png differ diff --git a/render-test/tests/gfx/fail-too-few-textures/metrics.json b/render-test/tests/gfx/fail-too-few-textures/metrics.json new file mode 100644 index 0000000000..805d7035e2 --- /dev/null +++ b/render-test/tests/gfx/fail-too-few-textures/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 1000, 63, 1, [371208, 371208], [68598, 68598], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/fail-too-few-textures/style.json b/render-test/tests/gfx/fail-too-few-textures/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-too-few-textures/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/fail-too-many-drawcalls/expected.png b/render-test/tests/gfx/fail-too-many-drawcalls/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-too-many-drawcalls/expected.png differ diff --git a/render-test/tests/gfx/fail-too-many-drawcalls/metrics.json b/render-test/tests/gfx/fail-too-many-drawcalls/metrics.json new file mode 100644 index 0000000000..9abb546450 --- /dev/null +++ b/render-test/tests/gfx/fail-too-many-drawcalls/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 28, 14, 63, 1, [371208, 371208], [68598, 68598], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/fail-too-many-drawcalls/style.json b/render-test/tests/gfx/fail-too-many-drawcalls/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-too-many-drawcalls/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/fail-vb-mem-mismatch/expected.png b/render-test/tests/gfx/fail-vb-mem-mismatch/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/fail-vb-mem-mismatch/expected.png differ diff --git a/render-test/tests/gfx/fail-vb-mem-mismatch/metrics.json b/render-test/tests/gfx/fail-vb-mem-mismatch/metrics.json new file mode 100644 index 0000000000..fd25dbd68b --- /dev/null +++ b/render-test/tests/gfx/fail-vb-mem-mismatch/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 14, 63, 1, [371208, 371208], [68598, 68598], [74592, 7654321]] + ] +} diff --git a/render-test/tests/gfx/fail-vb-mem-mismatch/style.json b/render-test/tests/gfx/fail-vb-mem-mismatch/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/fail-vb-mem-mismatch/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/pass-double-probe/expected.png b/render-test/tests/gfx/pass-double-probe/expected.png new file mode 100644 index 0000000000..9f4e48ab24 Binary files /dev/null and b/render-test/tests/gfx/pass-double-probe/expected.png differ diff --git a/render-test/tests/gfx/pass-double-probe/metrics.json b/render-test/tests/gfx/pass-double-probe/metrics.json new file mode 100644 index 0000000000..f2641a9a16 --- /dev/null +++ b/render-test/tests/gfx/pass-double-probe/metrics.json @@ -0,0 +1,6 @@ +{ + "gfx":[ + ["gfx 0", 36, 13, 63, 1, [240136, 240136], [68598, 68598], [74592, 74592]], + ["gfx 1", 32, 17, 85, 1, [325008, 325008], [84926, 84926], [100224, 100224]] + ] +} diff --git a/render-test/tests/gfx/pass-double-probe/style.json b/render-test/tests/gfx/pass-double-probe/style.json new file mode 100644 index 0000000000..395f4ce50a --- /dev/null +++ b/render-test/tests/gfx/pass-double-probe/style.json @@ -0,0 +1,22 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["setCenter", [-56.509552, -32.745788] ], + ["probeGFX", "gfx 1"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/pass-probe-reset/expected.png b/render-test/tests/gfx/pass-probe-reset/expected.png new file mode 100644 index 0000000000..9f4e48ab24 Binary files /dev/null and b/render-test/tests/gfx/pass-probe-reset/expected.png differ diff --git a/render-test/tests/gfx/pass-probe-reset/metrics.json b/render-test/tests/gfx/pass-probe-reset/metrics.json new file mode 100644 index 0000000000..0e42bc1697 --- /dev/null +++ b/render-test/tests/gfx/pass-probe-reset/metrics.json @@ -0,0 +1,6 @@ +{ + "gfx":[ + ["gfx 0", 36, 13, 63, 1, [240136, 240136], [68598, 68598], [74592, 74592]], + ["gfx 1", 32, 17, 85, 1, [84872, 84872], [16328, 16328], [25632, 25632]] + ] +} diff --git a/render-test/tests/gfx/pass-probe-reset/style.json b/render-test/tests/gfx/pass-probe-reset/style.json new file mode 100644 index 0000000000..698d95bb74 --- /dev/null +++ b/render-test/tests/gfx/pass-probe-reset/style.json @@ -0,0 +1,24 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.745788] ], + ["probeGFX", "gfx 1"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/gfx/pass/expected.png b/render-test/tests/gfx/pass/expected.png new file mode 100644 index 0000000000..4b5ea75a25 Binary files /dev/null and b/render-test/tests/gfx/pass/expected.png differ diff --git a/render-test/tests/gfx/pass/metrics.json b/render-test/tests/gfx/pass/metrics.json new file mode 100644 index 0000000000..67ecec5d78 --- /dev/null +++ b/render-test/tests/gfx/pass/metrics.json @@ -0,0 +1,5 @@ +{ + "gfx":[ + ["gfx 0", 36, 13, 63, 1, [240136, 240136], [68598, 68598], [74592, 74592]] + ] +} diff --git a/render-test/tests/gfx/pass/style.json b/render-test/tests/gfx/pass/style.json new file mode 100644 index 0000000000..6ae3eecb8c --- /dev/null +++ b/render-test/tests/gfx/pass/style.json @@ -0,0 +1,20 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512, + "operations": [ + ["setStyle", "local://styles/uruguay.json"], + ["setZoom", 9 ], + ["probeGFXStart"], + ["setCenter", [-56.509552, -32.865788] ], + ["probeGFX", "gfx 0"], + ["probeGFXEnd"] + ] + } + }, + "sources": {}, + "layers": [] + } + \ No newline at end of file diff --git a/render-test/tests/should-fail.json b/render-test/tests/should-fail.json index f08497b07f..b539d66019 100644 --- a/render-test/tests/should-fail.json +++ b/render-test/tests/should-fail.json @@ -7,5 +7,12 @@ "tests/network/fail-transferred": "Should fail, amount of transferred data higher than expected.", "tests/network/fail-requests-transferred": "Should fail, number of requests higher than expected and amount of transferred data less than expected.", "tests/memory/fail-memory-size-is-too-big": "Should fail, memory size is bigger than expected.", - "tests/memory/fail-memory-size-is-too-small": "Should fail, memory size is smaller than expected." + "tests/memory/fail-memory-size-is-too-small": "Should fail, memory size is smaller than expected.", + "tests/gfx/fail-ib-mem-mismatch": "Should fail, combined byte size of index buffers doesn't match the expectation.", + "tests/gfx/fail-negative-framebuffer-count": "Should fail, number of frame buffers is higher than expected.", + "tests/gfx/fail-texture-mem-mismatch": "Should fail, combined byte size of textures doesn't match the expectation.", + "tests/gfx/fail-too-many-drawcalls": "Should fail, number of draw calls higher than expected.", + "tests/gfx/fail-too-few-buffers": "Should fail, number of vertex and index buffers is smaller than expected.", + "tests/gfx/fail-too-few-textures": "Should fail, number of textures is smaller than expected.", + "tests/gfx/fail-vb-mem-mismatch": "Should fail, combined byte size of index buffers doesn't match the expectation." } -- cgit v1.2.1 From 8c498cd36c07b1019e5ddb60d5f9f8872f036e25 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 30 Oct 2019 11:30:54 +0200 Subject: [core] Introduce and apply GeoJSONData::create() API --- include/mbgl/style/sources/geojson_source.hpp | 16 +++++++++++ src/mbgl/style/sources/geojson_source.cpp | 20 +++++++------- src/mbgl/style/sources/geojson_source_impl.cpp | 37 ++++++++++++++------------ src/mbgl/style/sources/geojson_source_impl.hpp | 16 ++--------- 4 files changed, 49 insertions(+), 40 deletions(-) diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index a256ad6f15..c8dc65b912 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -34,6 +35,20 @@ struct GeoJSONOptions { using ClusterProperties = std::unordered_map; ClusterProperties clusterProperties; }; +class GeoJSONData { +public: + static std::shared_ptr create(const GeoJSON&, const GeoJSONOptions&); + + virtual ~GeoJSONData() = default; + virtual mapbox::feature::feature_collection getTile(const CanonicalTileID&) = 0; + + // SuperclusterData + virtual mapbox::feature::feature_collection getChildren(const std::uint32_t) = 0; + virtual mapbox::feature::feature_collection getLeaves(const std::uint32_t, + const std::uint32_t limit = 10u, + const std::uint32_t offset = 0u) = 0; + virtual std::uint8_t getClusterExpansionZoom(std::uint32_t) = 0; +}; class GeoJSONSource final : public Source { public: @@ -42,6 +57,7 @@ public: void setURL(const std::string& url); void setGeoJSON(const GeoJSON&); + void setGeoJSONData(std::shared_ptr); optional getURL() const; diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 5171c7c8d9..79e7c23459 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -32,8 +32,12 @@ void GeoJSONSource::setURL(const std::string& url_) { } void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) { + setGeoJSONData(GeoJSONData::create(geoJSON, impl().getOptions())); +} + +void GeoJSONSource::setGeoJSONData(std::shared_ptr geoJSONData) { req.reset(); - baseImpl = makeMutable(impl(), geoJSON); + baseImpl = makeMutable(impl(), std::move(geoJSONData)); observer->onSourceChanged(*this); } @@ -62,17 +66,15 @@ void GeoJSONSource::loadDescription(FileSource& fileSource) { *this, std::make_exception_ptr(std::runtime_error("unexpectedly empty GeoJSON"))); } else { conversion::Error error; - optional geoJSON = conversion::convertJSON(*res.data, error); - if (!geoJSON) { + std::shared_ptr geoJSONData; + if (optional geoJSON = conversion::convertJSON(*res.data, error)) { + geoJSONData = GeoJSONData::create(*geoJSON, impl().getOptions()); + } else { + // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for tiles to load. Log::Error(Event::ParseStyle, "Failed to parse GeoJSON data: %s", error.message.c_str()); - // Create an empty GeoJSON VT object to make sure we're not infinitely waiting for - // tiles to load. - baseImpl = makeMutable(impl(), GeoJSON{ FeatureCollection{} }); - } else { - baseImpl = makeMutable(impl(), *geoJSON); } - + baseImpl = makeMutable(impl(), std::move(geoJSONData)); loaded = true; observer->onSourceLoaded(*this); } diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index 8067b1ab1d..468deb6134 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -82,13 +82,8 @@ T evaluateFeature(const mapbox::feature::feature& f, return T(); } -GeoJSONSource::Impl::Impl(std::string id_, optional options_) - : Source::Impl(SourceType::GeoJSON, std::move(id_)) { - options = options_ ? std::move(*options_) : GeoJSONOptions{}; -} - -GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) - : Source::Impl(other), options(other.options) { +// static +std::shared_ptr GeoJSONData::create(const GeoJSON& geoJSON, const GeoJSONOptions& options) { constexpr double scale = util::EXTENT / util::tileSize; if (options.cluster && geoJSON.is>() && !geoJSON.get>().empty()) { @@ -116,19 +111,27 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) toReturn[p.first] = evaluateFeature(feature, p.second.second, accumulated); } }; - data = std::make_shared( - geoJSON.get>(), clusterOptions); - } else { - mapbox::geojsonvt::Options vtOptions; - vtOptions.maxZoom = options.maxzoom; - vtOptions.extent = util::EXTENT; - vtOptions.buffer = ::round(scale * options.buffer); - vtOptions.tolerance = scale * options.tolerance; - vtOptions.lineMetrics = options.lineMetrics; - data = std::make_shared(geoJSON, vtOptions); + return std::make_shared(geoJSON.get>(), + clusterOptions); } + + mapbox::geojsonvt::Options vtOptions; + vtOptions.maxZoom = options.maxzoom; + vtOptions.extent = util::EXTENT; + vtOptions.buffer = ::round(scale * options.buffer); + vtOptions.tolerance = scale * options.tolerance; + vtOptions.lineMetrics = options.lineMetrics; + return std::make_shared(geoJSON, vtOptions); } +GeoJSONSource::Impl::Impl(std::string id_, optional options_) + : Source::Impl(SourceType::GeoJSON, std::move(id_)) { + options = options_ ? std::move(*options_) : GeoJSONOptions{}; +} + +GeoJSONSource::Impl::Impl(const GeoJSONSource::Impl& other, std::shared_ptr data_) + : Source::Impl(other), options(other.options), data(std::move(data_)) {} + GeoJSONSource::Impl::~Impl() = default; Range GeoJSONSource::Impl::getZoomRange() const { diff --git a/src/mbgl/style/sources/geojson_source_impl.hpp b/src/mbgl/style/sources/geojson_source_impl.hpp index 26b9d95a39..da2673a38c 100644 --- a/src/mbgl/style/sources/geojson_source_impl.hpp +++ b/src/mbgl/style/sources/geojson_source_impl.hpp @@ -11,27 +11,15 @@ class CanonicalTileID; namespace style { -class GeoJSONData { -public: - virtual ~GeoJSONData() = default; - virtual mapbox::feature::feature_collection getTile(const CanonicalTileID&) = 0; - - // SuperclusterData - virtual mapbox::feature::feature_collection getChildren(const std::uint32_t) = 0; - virtual mapbox::feature::feature_collection getLeaves(const std::uint32_t, - const std::uint32_t limit = 10u, - const std::uint32_t offset = 0u) = 0; - virtual std::uint8_t getClusterExpansionZoom(std::uint32_t) = 0; -}; - class GeoJSONSource::Impl : public Source::Impl { public: Impl(std::string id, optional); - Impl(const GeoJSONSource::Impl&, const GeoJSON&); + Impl(const GeoJSONSource::Impl&, std::shared_ptr); ~Impl() final; Range getZoomRange() const; std::weak_ptr getData() const; + const GeoJSONOptions& getOptions() const { return options; } optional getAttribution() const final; -- cgit v1.2.1 From 4afb4438ebf0c8e7d4b4ae5fcfd10d363be6c3c7 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 30 Oct 2019 12:04:01 +0200 Subject: [android] Convert GeoJSON features to tiles in background Composing tiles from the GeoJSON features is an expensive operation that might block UI thread on updating the `GeoJsonSource` with the new data. This change moves tile composing to the background thread and thus unblocks the UI thread. --- include/mbgl/style/sources/geojson_source.hpp | 1 + .../android/src/style/sources/geojson_source.cpp | 82 ++++++++++------------ .../android/src/style/sources/geojson_source.hpp | 20 ++++-- src/mbgl/style/sources/geojson_source.cpp | 4 ++ 4 files changed, 56 insertions(+), 51 deletions(-) diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index c8dc65b912..549393e9b2 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -60,6 +60,7 @@ public: void setGeoJSONData(std::shared_ptr); optional getURL() const; + const GeoJSONOptions& getOptions() const; class Impl; const Impl& impl() const; diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 5ff4864275..0eece4b1ad 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -44,18 +44,16 @@ namespace android { } GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, const jni::String& sourceId, const jni::Object<>& options) - : Source(env, std::make_unique( - jni::Make(env, sourceId), - convertGeoJSONOptions(env, options))) - , converter(std::make_unique>(Scheduler::GetBackground())) { - } + : Source(env, + std::make_unique(jni::Make(env, sourceId), + convertGeoJSONOptions(env, options))), + converter(std::make_unique>(Scheduler::GetBackground(), + source.as()->getOptions())) {} - GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, - mbgl::style::Source& coreSource, - AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) - , converter(std::make_unique>(Scheduler::GetBackground())) { - } + GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) + : Source(env, coreSource, createJavaPeer(env), frontend), + converter(std::make_unique>(Scheduler::GetBackground(), + source.as()->getOptions())) {} GeoJSONSource::~GeoJSONSource() = default; @@ -63,7 +61,7 @@ namespace android { std::shared_ptr json = std::make_shared(jni::Make(env, jString)); - Update::Converter converterFn = [this, json](ActorRef _callback) { + Update::Converter converterFn = [this, json](ActorRef _callback) { converter->self().invoke(&FeatureConverter::convertJson, json, _callback); }; @@ -84,11 +82,11 @@ namespace android { void GeoJSONSource::setURL(jni::JNIEnv& env, const jni::String& url) { // Update the core source - source.as()->GeoJSONSource::setURL(jni::Make(env, url)); + source.as()->setURL(jni::Make(env, url)); } jni::Local GeoJSONSource::getURL(jni::JNIEnv& env) { - optional url = source.as()->GeoJSONSource::getURL(); + optional url = source.as()->getURL(); return url ? jni::Make(env, *url) : jni::Local(); } @@ -166,7 +164,7 @@ namespace android { auto global = jni::NewGlobal(env, jObject); auto object = std::make_shared(std::move(global)); - Update::Converter converterFn = [this, object](ActorRef _callback) { + Update::Converter converterFn = [this, object](ActorRef _callback) { converter->self().invoke(&FeatureConverter::convertObject, object, _callback); }; @@ -175,25 +173,23 @@ namespace android { void GeoJSONSource::setAsync(Update::Converter converterFn) { awaitingUpdate = std::make_unique( - std::move(converterFn), - std::make_unique>( - *Scheduler::GetCurrent(), - [this](GeoJSON geoJSON) { - // conversion from Java features to core ones finished - android::UniqueEnv _env = android::AttachEnv(); - - // Update the core source - source.as()->GeoJSONSource::setGeoJSON(geoJSON); - - // if there is an awaiting update, execute it, otherwise, release resources - if (awaitingUpdate) { - update = std::move(awaitingUpdate); - update->converterFn(update->callback->self()); - } else { - update.reset(); - } - }) - ); + std::move(converterFn), + std::make_unique>( + *Scheduler::GetCurrent(), [this](std::shared_ptr geoJSONData) { + // conversion from Java features to core ones finished + android::UniqueEnv _env = android::AttachEnv(); + + // Update the core source + source.as()->setGeoJSONData(std::move(geoJSONData)); + + // if there is an awaiting update, execute it, otherwise, release resources + if (awaitingUpdate) { + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } else { + update.reset(); + } + })); // If another update is running, wait if (update) { @@ -230,12 +226,10 @@ namespace android { ); } - void FeatureConverter::convertJson(std::shared_ptr json, - ActorRef callback) { + void FeatureConverter::convertJson(std::shared_ptr json, ActorRef callback) { using namespace mbgl::style::conversion; android::UniqueEnv _env = android::AttachEnv(); - // Convert the jni object Error error; optional converted = parseGeoJSON(*json, error); @@ -243,23 +237,23 @@ namespace android { mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); return; } - - callback.invoke(&Callback::operator(), *converted); + callback.invoke(&GeoJSONDataCallback::operator(), style::GeoJSONData::create(*converted, options)); } template - void FeatureConverter::convertObject(std::shared_ptr, jni::EnvAttachingDeleter>> jObject, ActorRef callback) { + void FeatureConverter::convertObject( + std::shared_ptr, jni::EnvAttachingDeleter>> jObject, + ActorRef callback) { using namespace mbgl::android::geojson; android::UniqueEnv _env = android::AttachEnv(); // Convert the jni object auto geometry = JNIType::convert(*_env, *jObject); - callback.invoke(&Callback::operator(), GeoJSON(geometry)); + callback.invoke(&GeoJSONDataCallback::operator(), style::GeoJSONData::create(geometry, options)); } - Update::Update(Converter _converterFn, std::unique_ptr> _callback) - : converterFn(std::move(_converterFn)) - , callback(std::move(_callback)) {} + Update::Update(Converter _converterFn, std::unique_ptr> _callback) + : converterFn(std::move(_converterFn)), callback(std::move(_callback)) {} } // namespace android } // namespace mbgl diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp index e737e41924..e506191ceb 100644 --- a/platform/android/src/style/sources/geojson_source.hpp +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -11,22 +11,28 @@ namespace mbgl { namespace android { -using Callback = std::function; +using GeoJSONDataCallback = std::function)>; -struct FeatureConverter { - void convertJson(std::shared_ptr, ActorRef); +class FeatureConverter { +public: + explicit FeatureConverter(style::GeoJSONOptions options_) : options(std::move(options_)) {} + void convertJson(std::shared_ptr, ActorRef); template - void convertObject(std::shared_ptr, jni::EnvAttachingDeleter>>, ActorRef); + void convertObject(std::shared_ptr, jni::EnvAttachingDeleter>>, + ActorRef); + +private: + style::GeoJSONOptions options; }; struct Update { - using Converter = std::function)>; + using Converter = std::function)>; Converter converterFn; - std::unique_ptr> callback; + std::unique_ptr> callback; - Update(Converter, std::unique_ptr>); + Update(Converter, std::unique_ptr>); }; class GeoJSONSource : public Source { diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 79e7c23459..3832977cd4 100644 --- a/src/mbgl/style/sources/geojson_source.cpp +++ b/src/mbgl/style/sources/geojson_source.cpp @@ -45,6 +45,10 @@ optional GeoJSONSource::getURL() const { return url; } +const GeoJSONOptions& GeoJSONSource::getOptions() const { + return impl().getOptions(); +} + void GeoJSONSource::loadDescription(FileSource& fileSource) { if (!url) { loaded = true; -- cgit v1.2.1 From 5b38cfee18800cbb3c6a3186882744592662c3d6 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Wed, 30 Oct 2019 14:58:56 +0200 Subject: [android] Add change log entry --- platform/android/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 7722736100..398844a64e 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ### Performance improvements - Enable incremental vacuum for the offline database in order to make data removal requests faster and to avoid the excessive disk space usage (creating a backup file on VACUUM call) [#15837](https://github.com/mapbox/mapbox-gl-native/pull/15837) + - Convert GeoJSON features to tiles in a background thread and thus unblock the UI thread on updating the GeoJsonSource [#15871](https://github.com/mapbox/mapbox-gl-native/pull/15871) ## 8.5.0-alpha.2 - October 10, 2019 [Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.5.0-alpha.1...android-v8.5.0-alpha.2) since [Mapbox Maps SDK for Android v8.5.0-alpha.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.5.0-alpha.1): -- cgit v1.2.1