summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/core-files.json1
-rwxr-xr-xplatform/android/src/jni.cpp2
-rw-r--r--platform/android/src/text/format_number.cpp81
-rw-r--r--platform/android/src/text/format_number_jni.hpp29
-rw-r--r--platform/darwin/src/string_nsstring.mm23
-rw-r--r--platform/default/src/mbgl/util/format_number.cpp35
-rw-r--r--platform/linux/config.cmake14
-rw-r--r--platform/node/src/node_expression.cpp3
-rw-r--r--platform/qt/qt.cmake1
-rw-r--r--platform/qt/src/format_number.cpp26
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