diff options
Diffstat (limited to 'platform')
-rw-r--r-- | platform/android/core-files.json | 1 | ||||
-rwxr-xr-x | platform/android/src/jni.cpp | 2 | ||||
-rw-r--r-- | platform/android/src/text/format_number.cpp | 81 | ||||
-rw-r--r-- | platform/android/src/text/format_number_jni.hpp | 29 | ||||
-rw-r--r-- | platform/darwin/src/string_nsstring.mm | 23 | ||||
-rw-r--r-- | platform/default/src/mbgl/util/format_number.cpp | 35 | ||||
-rw-r--r-- | platform/linux/config.cmake | 14 | ||||
-rw-r--r-- | platform/node/src/node_expression.cpp | 3 | ||||
-rw-r--r-- | platform/qt/qt.cmake | 1 | ||||
-rw-r--r-- | platform/qt/src/format_number.cpp | 26 |
10 files changed, 213 insertions, 2 deletions
diff --git a/platform/android/core-files.json b/platform/android/core-files.json index 7e2f7cc07b..62ecc0c671 100644 --- a/platform/android/core-files.json +++ b/platform/android/core-files.json @@ -81,6 +81,7 @@ "platform/android/src/style/value.cpp", "platform/android/src/text/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", diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index 410c962384..088b3b796c 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -54,6 +54,7 @@ #endif #include "text/collator_jni.hpp" #include "text/local_glyph_rasterizer_jni.hpp" +#include "text/format_number_jni.hpp" #include "logger.hpp" namespace mbgl { @@ -200,6 +201,7 @@ void registerNatives(JavaVM *vm) { Locale::registerNative(env); Collator::registerNative(env); StringUtils::registerNative(env); + NumberFormat::registerNative(env); // Logger Logger::registerNative(env); diff --git a/platform/android/src/text/format_number.cpp b/platform/android/src/text/format_number.cpp new file mode 100644 index 0000000000..3a41175ecc --- /dev/null +++ b/platform/android/src/text/format_number.cpp @@ -0,0 +1,81 @@ +#include <mbgl/style/expression/collator.hpp> +#include <mbgl/text/language_tag.hpp> +#include <mbgl/util/platform.hpp> + +#include <jni/jni.hpp> + +#include "../attach_env.hpp" +#include "format_number_jni.hpp" + +namespace mbgl { +namespace android { + +void NumberFormat::registerNative(jni::JNIEnv& env) { + jni::Class<NumberFormat>::Singleton(env); +} + +jni::Local<jni::Object<NumberFormat>> NumberFormat::getInstance(jni::JNIEnv& env, const jni::Object<Locale>& locale) { + static auto& javaClass = jni::Class<NumberFormat>::Singleton(env); + static auto method = javaClass.GetStaticMethod<jni::Object<NumberFormat> (jni::Object<Locale>)>(env, "getInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local<jni::Object<NumberFormat>> NumberFormat::getCurrencyInstance(jni::JNIEnv& env, const jni::Object<Locale>& locale) { + static auto& javaClass = jni::Class<NumberFormat>::Singleton(env); + static auto method = javaClass.GetStaticMethod<jni::Object<NumberFormat> (jni::Object<Locale>)>(env, "getCurrencyInstance"); + return javaClass.Call(env, method, locale); +} + +jni::Local<jni::String> NumberFormat::format(jni::JNIEnv& env, const jni::Object<NumberFormat>& nf, jni::jdouble number) { + static auto& javaClass = jni::Class<NumberFormat>::Singleton(env); + static auto method = javaClass.GetMethod<jni::String (jni::jdouble)>(env, "format"); + return nf.Call(env, method, number); +} + +void NumberFormat::setMinimumFractionDigits(jni::JNIEnv& env, const jni::Object<NumberFormat>& nf, jni::jint value) { + static auto& javaClass = jni::Class<NumberFormat>::Singleton(env); + static auto method = javaClass.GetMethod<void (jni::jint)>(env, "setMinimumFractionDigits"); + return nf.Call(env, method, value); +} + +void NumberFormat::setMaximumFractionDigits(jni::JNIEnv& env, const jni::Object<NumberFormat>& nf, jni::jint value) { + static auto& javaClass = jni::Class<NumberFormat>::Singleton(env); + static auto method = javaClass.GetMethod<void (jni::jint)>(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<jni::Object<android::Locale>> 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<jni::String>(*env, *languageTag.language))); + } else { + locale = jni::NewGlobal(*env, android::Locale::New(*env, jni::Make<jni::String>(*env, *languageTag.language), + jni::Make<jni::String>(*env, *languageTag.region))); + } + + jni::Global<jni::Object<android::NumberFormat>> formatter; + if (currency.empty()) { + formatter = jni::NewGlobal(*env, android::NumberFormat::getInstance(*env, locale)); + android::NumberFormat::setMinimumFractionDigits(*env, formatter, static_cast<jni::jint>(minFractionDigits)); + android::NumberFormat::setMaximumFractionDigits(*env, formatter, static_cast<jni::jint>(maxFractionDigits)); + } else { + formatter = jni::NewGlobal(*env, android::NumberFormat::getCurrencyInstance(*env, locale)); + } + + auto result = android::NumberFormat::format(*env, formatter, static_cast<jni::jdouble>(number)); + return jni::Make<std::string>(*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 new file mode 100644 index 0000000000..1720038925 --- /dev/null +++ b/platform/android/src/text/format_number_jni.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include <jni/jni.hpp> + +#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<jni::Object<NumberFormat>> getInstance(jni::JNIEnv&, const jni::Object<Locale>&); + static jni::Local<jni::Object<NumberFormat>> getCurrencyInstance(jni::JNIEnv&, const jni::Object<Locale>&); + static jni::Local<jni::String> format(jni::JNIEnv&, const jni::Object<NumberFormat>&, jni::jdouble); + static void setMinimumFractionDigits(jni::JNIEnv&, const jni::Object<NumberFormat>&, jni::jint); + static void setMaximumFractionDigits(jni::JNIEnv&, const jni::Object<NumberFormat>&, jni::jint); + + static void registerNative(jni::JNIEnv&); +}; + +} // namespace android +} // namespace mbgl diff --git a/platform/darwin/src/string_nsstring.mm b/platform/darwin/src/string_nsstring.mm index 08f9aeccef..096ed2b212 100644 --- a/platform/darwin/src/string_nsstring.mm +++ b/platform/darwin/src/string_nsstring.mm @@ -27,5 +27,28 @@ 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 { + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + } + NSString *formatted = [numberFormatter stringFromNumber:@(number)]; + std::string result = std::string([formatted UTF8String]); + return result; +} + } } diff --git a/platform/default/src/mbgl/util/format_number.cpp b/platform/default/src/mbgl/util/format_number.cpp new file mode 100644 index 0000000000..7cc863818a --- /dev/null +++ b/platform/default/src/mbgl/util/format_number.cpp @@ -0,0 +1,35 @@ +#include <mbgl/util/platform.hpp> + +#include <unicode/numberformatter.h> + +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() + .precision(icu::number::Precision::minMaxFraction(minFractionDigits, maxFractionDigits)) + .locale(locale) + .formatDouble(number, status) + .toString(); + } + return ustr.toUTF8String(formatted); +} + +} // namespace platform +} // namespace mbgl diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 7cc1f1fe4d..aa65ddb606 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -56,6 +56,7 @@ macro(mbgl_platform_core) 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 # Image handling PRIVATE platform/default/src/mbgl/util/image.cpp @@ -83,10 +84,21 @@ macro(mbgl_platform_core) target_add_mason_package(mbgl-core PUBLIC libpng) target_add_mason_package(mbgl-core PUBLIC libjpeg-turbo) + 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) + + # Link all ICU libraries (by default only libicuuc is linked) + find_library(LIBICUI18N NAMES icui18n HINTS ${MASON_PACKAGE_icu_INCLUDE_DIRS}/../lib) + find_library(LIBICUUC NAMES icuuc HINTS ${MASON_PACKAGE_icu_INCLUDE_DIRS}/../lib) + find_library(LIBICUDATA NAMES icudata HINTS ${MASON_PACKAGE_icu_INCLUDE_DIRS}/../lib) target_link_libraries(mbgl-core + PRIVATE ${LIBICUI18N} + PRIVATE ${LIBICUUC} + PRIVATE ${LIBICUDATA} PRIVATE nunicode - PRIVATE icu PUBLIC -lz ) diff --git a/platform/node/src/node_expression.cpp b/platform/node/src/node_expression.cpp index 4ea66124f8..041f60d029 100644 --- a/platform/node/src/node_expression.cpp +++ b/platform/node/src/node_expression.cpp @@ -42,7 +42,8 @@ type::Type parseType(v8::Local<v8::Object> type) { {"object", type::Object}, {"color", type::Color}, {"value", type::Value}, - {"formatted", type::Formatted} + {"formatted", type::Formatted}, + {"number-format", type::String} }; v8::Local<v8::Value> v8kind = Nan::Get(type, Nan::New("kind").ToLocalChecked()).ToLocalChecked(); diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake index 48523057c9..33acb7a030 100644 --- a/platform/qt/qt.cmake +++ b/platform/qt/qt.cmake @@ -35,6 +35,7 @@ set(MBGL_QT_CORE_FILES PRIVATE platform/qt/src/timer_impl.hpp PRIVATE platform/qt/src/utf.cpp PRIVATE platform/qt/src/gl_functions.cpp + PRIVATE platform/qt/src/format_number.cpp PRIVATE platform/default/src/mbgl/text/collator.cpp PRIVATE platform/default/src/mbgl/text/unaccent.cpp diff --git a/platform/qt/src/format_number.cpp b/platform/qt/src/format_number.cpp new file mode 100644 index 0000000000..b6fe3558e6 --- /dev/null +++ b/platform/qt/src/format_number.cpp @@ -0,0 +1,26 @@ +#include <mbgl/util/platform.hpp> + +#include <QLocale> +#include <QString> + +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 |