LCOV - code coverage report
Current view: top level - intl/unicharutil/util - ICUUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 76 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       3             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #ifdef MOZILLA_INTERNAL_API
       6             : #ifdef ENABLE_INTL_API
       7             : 
       8             : #include "ICUUtils.h"
       9             : #include "mozilla/Preferences.h"
      10             : #include "mozilla/intl/LocaleService.h"
      11             : #include "nsIContent.h"
      12             : #include "nsIDocument.h"
      13             : #include "nsStringGlue.h"
      14             : #include "unicode/uloc.h"
      15             : #include "unicode/unum.h"
      16             : 
      17             : using namespace mozilla;
      18             : using mozilla::intl::LocaleService;
      19             : 
      20             : /**
      21             :  * This pref just controls whether we format the number with grouping separator
      22             :  * characters when the internal value is set or updated. It does not stop the
      23             :  * user from typing in a number and using grouping separators.
      24             :  */
      25             : static bool gLocaleNumberGroupingEnabled;
      26             : static const char LOCALE_NUMBER_GROUPING_PREF_STR[] = "dom.forms.number.grouping";
      27             : 
      28             : static bool
      29           0 : LocaleNumberGroupingIsEnabled()
      30             : {
      31             :   static bool sInitialized = false;
      32             : 
      33           0 :   if (!sInitialized) {
      34             :     /* check and register ourselves with the pref */
      35             :     Preferences::AddBoolVarCache(&gLocaleNumberGroupingEnabled,
      36             :                                  LOCALE_NUMBER_GROUPING_PREF_STR,
      37           0 :                                  false);
      38           0 :     sInitialized = true;
      39             :   }
      40             : 
      41           0 :   return gLocaleNumberGroupingEnabled;
      42             : }
      43             : 
      44             : void
      45           0 : ICUUtils::LanguageTagIterForContent::GetNext(nsACString& aBCP47LangTag)
      46             : {
      47           0 :   if (mCurrentFallbackIndex < 0) {
      48           0 :     mCurrentFallbackIndex = 0;
      49             :     // Try the language specified by a 'lang'/'xml:lang' attribute on mContent
      50             :     // or any ancestor, if such an attribute is specified:
      51           0 :     nsAutoString lang;
      52           0 :     mContent->GetLang(lang);
      53           0 :     if (!lang.IsEmpty()) {
      54           0 :       aBCP47LangTag = NS_ConvertUTF16toUTF8(lang);
      55           0 :       return;
      56             :     }
      57             :   }
      58             : 
      59           0 :   if (mCurrentFallbackIndex < 1) {
      60           0 :     mCurrentFallbackIndex = 1;
      61             :     // Else try the language specified by any Content-Language HTTP header or
      62             :     // pragma directive:
      63           0 :     nsIDocument* doc = mContent->OwnerDoc();
      64           0 :     nsAutoString lang;
      65           0 :     doc->GetContentLanguage(lang);
      66           0 :     if (!lang.IsEmpty()) {
      67           0 :       aBCP47LangTag = NS_ConvertUTF16toUTF8(lang);
      68           0 :       return;
      69             :     }
      70             :   }
      71             : 
      72           0 :   if (mCurrentFallbackIndex < 2) {
      73           0 :     mCurrentFallbackIndex = 2;
      74             :     // Else take the app's locale:
      75             : 
      76           0 :     nsAutoCString appLocale;
      77           0 :     LocaleService::GetInstance()->GetAppLocaleAsBCP47(aBCP47LangTag);
      78           0 :     return;
      79             :   }
      80             : 
      81             :   // TODO: Probably not worth it, but maybe have a fourth fallback to using
      82             :   // the OS locale?
      83             : 
      84           0 :   aBCP47LangTag.Truncate(); // Signal iterator exhausted
      85             : }
      86             : 
      87             : /* static */ bool
      88           0 : ICUUtils::LocalizeNumber(double aValue,
      89             :                          LanguageTagIterForContent& aLangTags,
      90             :                          nsAString& aLocalizedValue)
      91             : {
      92           0 :   MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing");
      93             : 
      94             :   static const int32_t kBufferSize = 256;
      95             : 
      96             :   UChar buffer[kBufferSize];
      97             : 
      98           0 :   nsAutoCString langTag;
      99           0 :   aLangTags.GetNext(langTag);
     100           0 :   while (!langTag.IsEmpty()) {
     101           0 :     UErrorCode status = U_ZERO_ERROR;
     102           0 :     AutoCloseUNumberFormat format(unum_open(UNUM_DECIMAL, nullptr, 0,
     103           0 :                                             langTag.get(), nullptr, &status));
     104           0 :     unum_setAttribute(format, UNUM_GROUPING_USED,
     105           0 :                       LocaleNumberGroupingIsEnabled());
     106             :     // ICU default is a maximum of 3 significant fractional digits. We don't
     107             :     // want that limit, so we set it to the maximum that a double can represent
     108             :     // (14-16 decimal fractional digits).
     109           0 :     unum_setAttribute(format, UNUM_MAX_FRACTION_DIGITS, 16);
     110           0 :     int32_t length = unum_formatDouble(format, aValue, buffer, kBufferSize,
     111           0 :                                        nullptr, &status);
     112           0 :     NS_ASSERTION(length < kBufferSize &&
     113             :                  status != U_BUFFER_OVERFLOW_ERROR &&
     114             :                  status != U_STRING_NOT_TERMINATED_WARNING,
     115             :                  "Need a bigger buffer?!");
     116           0 :     if (U_SUCCESS(status)) {
     117           0 :       ICUUtils::AssignUCharArrayToString(buffer, length, aLocalizedValue);
     118           0 :       return true;
     119             :     }
     120           0 :     aLangTags.GetNext(langTag);
     121             :   }
     122           0 :   return false;
     123             : }
     124             : 
     125             : /* static */ double
     126           0 : ICUUtils::ParseNumber(nsAString& aValue,
     127             :                       LanguageTagIterForContent& aLangTags)
     128             : {
     129           0 :   MOZ_ASSERT(aLangTags.IsAtStart(), "Don't call Next() before passing");
     130             : 
     131           0 :   if (aValue.IsEmpty()) {
     132           0 :     return std::numeric_limits<float>::quiet_NaN();
     133             :   }
     134             : 
     135           0 :   uint32_t length = aValue.Length();
     136             : 
     137           0 :   nsAutoCString langTag;
     138           0 :   aLangTags.GetNext(langTag);
     139           0 :   while (!langTag.IsEmpty()) {
     140           0 :     UErrorCode status = U_ZERO_ERROR;
     141           0 :     AutoCloseUNumberFormat format(unum_open(UNUM_DECIMAL, nullptr, 0,
     142           0 :                                             langTag.get(), nullptr, &status));
     143           0 :     int32_t parsePos = 0;
     144             :     static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
     145             :                   "Unexpected character size - the following cast is unsafe");
     146           0 :     double val = unum_parseDouble(format,
     147           0 :                                   (const UChar*)PromiseFlatString(aValue).get(),
     148           0 :                                   length, &parsePos, &status);
     149           0 :     if (U_SUCCESS(status) && parsePos == (int32_t)length) {
     150           0 :       return val;
     151             :     }
     152           0 :     aLangTags.GetNext(langTag);
     153             :   }
     154           0 :   return std::numeric_limits<float>::quiet_NaN();
     155             : }
     156             : 
     157             : /* static */ void
     158           0 : ICUUtils::AssignUCharArrayToString(UChar* aICUString,
     159             :                                    int32_t aLength,
     160             :                                    nsAString& aMozString)
     161             : {
     162             :   // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can
     163             :   // cast here.
     164             : 
     165             :   static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
     166             :                 "Unexpected character size - the following cast is unsafe");
     167             : 
     168           0 :   aMozString.Assign((const nsAString::char_type*)aICUString, aLength);
     169             : 
     170           0 :   NS_ASSERTION((int32_t)aMozString.Length() == aLength, "Conversion failed");
     171           0 : }
     172             : 
     173             : /* static */ nsresult
     174           0 : ICUUtils::UErrorToNsResult(const UErrorCode aErrorCode)
     175             : {
     176           0 :   if (U_SUCCESS(aErrorCode)) {
     177           0 :     return NS_OK;
     178             :   }
     179             : 
     180           0 :   switch(aErrorCode) {
     181             :     case U_ILLEGAL_ARGUMENT_ERROR:
     182           0 :       return NS_ERROR_INVALID_ARG;
     183             : 
     184             :     case U_MEMORY_ALLOCATION_ERROR:
     185           0 :       return NS_ERROR_OUT_OF_MEMORY;
     186             : 
     187             :     default:
     188           0 :       return NS_ERROR_FAILURE;
     189             :   }
     190             : }
     191             : 
     192             : #if 0
     193             : /* static */ Locale
     194             : ICUUtils::BCP47CodeToLocale(const nsAString& aBCP47Code)
     195             : {
     196             :   MOZ_ASSERT(!aBCP47Code.IsEmpty(), "Don't pass an empty BCP 47 code");
     197             : 
     198             :   Locale locale;
     199             :   locale.setToBogus();
     200             : 
     201             :   // BCP47 codes are guaranteed to be ASCII, so lossy conversion is okay
     202             :   NS_LossyConvertUTF16toASCII bcp47code(aBCP47Code);
     203             : 
     204             :   UErrorCode status = U_ZERO_ERROR;
     205             :   int32_t needed;
     206             : 
     207             :   char localeID[256];
     208             :   needed = uloc_forLanguageTag(bcp47code.get(), localeID,
     209             :                                PR_ARRAY_SIZE(localeID) - 1, nullptr,
     210             :                                &status);
     211             :   MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(localeID)) - 1,
     212             :              "Need a bigger buffer");
     213             :   if (needed <= 0 || U_FAILURE(status)) {
     214             :     return locale;
     215             :   }
     216             : 
     217             :   char lang[64];
     218             :   needed = uloc_getLanguage(localeID, lang, PR_ARRAY_SIZE(lang) - 1,
     219             :                             &status);
     220             :   MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(lang)) - 1,
     221             :              "Need a bigger buffer");
     222             :   if (needed <= 0 || U_FAILURE(status)) {
     223             :     return locale;
     224             :   }
     225             : 
     226             :   char country[64];
     227             :   needed = uloc_getCountry(localeID, country, PR_ARRAY_SIZE(country) - 1,
     228             :                            &status);
     229             :   MOZ_ASSERT(needed < int32_t(PR_ARRAY_SIZE(country)) - 1,
     230             :              "Need a bigger buffer");
     231             :   if (needed > 0 && U_SUCCESS(status)) {
     232             :     locale = Locale(lang, country);
     233             :   }
     234             : 
     235             :   if (locale.isBogus()) {
     236             :     // Using the country resulted in a bogus Locale, so try with only the lang
     237             :     locale = Locale(lang);
     238             :   }
     239             : 
     240             :   return locale;
     241             : }
     242             : 
     243             : /* static */ void
     244             : ICUUtils::ToMozString(UnicodeString& aICUString, nsAString& aMozString)
     245             : {
     246             :   // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can
     247             :   // cast here.
     248             : 
     249             :   static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
     250             :                 "Unexpected character size - the following cast is unsafe");
     251             : 
     252             :   const nsAString::char_type* buf =
     253             :     (const nsAString::char_type*)aICUString.getTerminatedBuffer();
     254             :   aMozString.Assign(buf);
     255             : 
     256             :   NS_ASSERTION(aMozString.Length() == (uint32_t)aICUString.length(),
     257             :                "Conversion failed");
     258             : }
     259             : 
     260             : /* static */ void
     261             : ICUUtils::ToICUString(nsAString& aMozString, UnicodeString& aICUString)
     262             : {
     263             :   // Both ICU's UnicodeString and Mozilla's nsAString use UTF-16, so we can
     264             :   // cast here.
     265             : 
     266             :   static_assert(sizeof(UChar) == 2 && sizeof(nsAString::char_type) == 2,
     267             :                 "Unexpected character size - the following cast is unsafe");
     268             : 
     269             :   aICUString.setTo((UChar*)PromiseFlatString(aMozString).get(),
     270             :                    aMozString.Length());
     271             : 
     272             :   NS_ASSERTION(aMozString.Length() == (uint32_t)aICUString.length(),
     273             :                "Conversion failed");
     274             : }
     275             : #endif
     276             : 
     277             : #endif /* ENABLE_INTL_API */
     278             : #endif /* MOZILLA_INTERNAL_API */
     279             : 

Generated by: LCOV version 1.13