LCOV - code coverage report
Current view: top level - src/objects - intl-objects.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 355 439 80.9 %
Date: 2017-10-20 Functions: 30 31 96.8 %

          Line data    Source code
       1             : // Copyright 2013 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #ifndef V8_INTL_SUPPORT
       6             : #error Internationalization is expected to be enabled.
       7             : #endif  // V8_INTL_SUPPORT
       8             : 
       9             : #include "src/objects/intl-objects.h"
      10             : 
      11             : #include <memory>
      12             : 
      13             : #include "src/api.h"
      14             : #include "src/factory.h"
      15             : #include "src/isolate.h"
      16             : #include "src/objects-inl.h"
      17             : #include "src/property-descriptor.h"
      18             : #include "unicode/brkiter.h"
      19             : #include "unicode/bytestream.h"
      20             : #include "unicode/calendar.h"
      21             : #include "unicode/coll.h"
      22             : #include "unicode/curramt.h"
      23             : #include "unicode/dcfmtsym.h"
      24             : #include "unicode/decimfmt.h"
      25             : #include "unicode/dtfmtsym.h"
      26             : #include "unicode/dtptngen.h"
      27             : #include "unicode/gregocal.h"
      28             : #include "unicode/locid.h"
      29             : #include "unicode/numfmt.h"
      30             : #include "unicode/numsys.h"
      31             : #include "unicode/plurrule.h"
      32             : #include "unicode/rbbi.h"
      33             : #include "unicode/smpdtfmt.h"
      34             : #include "unicode/timezone.h"
      35             : #include "unicode/uchar.h"
      36             : #include "unicode/ucol.h"
      37             : #include "unicode/ucurr.h"
      38             : #include "unicode/unum.h"
      39             : #include "unicode/upluralrules.h"
      40             : #include "unicode/uvernum.h"
      41             : #include "unicode/uversion.h"
      42             : 
      43             : #if U_ICU_VERSION_MAJOR_NUM >= 59
      44             : #include "unicode/char16ptr.h"
      45             : #endif
      46             : 
      47             : namespace v8 {
      48             : namespace internal {
      49             : 
      50             : namespace {
      51             : 
      52       22129 : bool ExtractStringSetting(Isolate* isolate, Handle<JSObject> options,
      53             :                           const char* key, icu::UnicodeString* setting) {
      54             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
      55       22129 :   Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
      56             :   Handle<Object> object =
      57       44258 :       JSReceiver::GetProperty(options, str).ToHandleChecked();
      58       22129 :   if (object->IsString()) {
      59             :     v8::String::Utf8Value utf8_string(
      60       12089 :         v8_isolate, v8::Utils::ToLocal(Handle<String>::cast(object)));
      61       24178 :     *setting = icu::UnicodeString::fromUTF8(*utf8_string);
      62       12089 :     return true;
      63             :   }
      64             :   return false;
      65             : }
      66             : 
      67        3180 : bool ExtractIntegerSetting(Isolate* isolate, Handle<JSObject> options,
      68             :                            const char* key, int32_t* value) {
      69        3180 :   Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
      70             :   Handle<Object> object =
      71        6360 :       JSReceiver::GetProperty(options, str).ToHandleChecked();
      72        3180 :   if (object->IsNumber()) {
      73        1962 :     object->ToInt32(value);
      74        1962 :     return true;
      75             :   }
      76             :   return false;
      77             : }
      78             : 
      79       20041 : bool ExtractBooleanSetting(Isolate* isolate, Handle<JSObject> options,
      80             :                            const char* key, bool* value) {
      81       20041 :   Handle<String> str = isolate->factory()->NewStringFromAsciiChecked(key);
      82             :   Handle<Object> object =
      83       40082 :       JSReceiver::GetProperty(options, str).ToHandleChecked();
      84       20041 :   if (object->IsBoolean()) {
      85       10325 :     *value = object->BooleanValue();
      86       10325 :     return true;
      87             :   }
      88             :   return false;
      89             : }
      90             : 
      91         847 : icu::SimpleDateFormat* CreateICUDateFormat(Isolate* isolate,
      92             :                                            const icu::Locale& icu_locale,
      93             :                                            Handle<JSObject> options) {
      94             :   // Create time zone as specified by the user. We have to re-create time zone
      95             :   // since calendar takes ownership.
      96             :   icu::TimeZone* tz = nullptr;
      97             :   icu::UnicodeString timezone;
      98         847 :   if (ExtractStringSetting(isolate, options, "timeZone", &timezone)) {
      99         316 :     tz = icu::TimeZone::createTimeZone(timezone);
     100             :   } else {
     101         531 :     tz = icu::TimeZone::createDefault();
     102             :   }
     103             : 
     104             :   // Create a calendar using locale, and apply time zone to it.
     105         847 :   UErrorCode status = U_ZERO_ERROR;
     106             :   icu::Calendar* calendar =
     107         847 :       icu::Calendar::createInstance(tz, icu_locale, status);
     108             : 
     109        1694 :   if (calendar->getDynamicClassID() ==
     110         847 :       icu::GregorianCalendar::getStaticClassID()) {
     111             :     icu::GregorianCalendar* gc = (icu::GregorianCalendar*)calendar;
     112         793 :     UErrorCode status = U_ZERO_ERROR;
     113             :     // The beginning of ECMAScript time, namely -(2**53)
     114             :     const double start_of_time = -9007199254740992;
     115         793 :     gc->setGregorianChange(start_of_time, status);
     116             :     DCHECK(U_SUCCESS(status));
     117             :   }
     118             : 
     119             :   // Make formatter from skeleton. Calendar and numbering system are added
     120             :   // to the locale as Unicode extension (if they were specified at all).
     121             :   icu::SimpleDateFormat* date_format = nullptr;
     122         847 :   icu::UnicodeString skeleton;
     123         847 :   if (ExtractStringSetting(isolate, options, "skeleton", &skeleton)) {
     124             :     std::unique_ptr<icu::DateTimePatternGenerator> generator(
     125         847 :         icu::DateTimePatternGenerator::createInstance(icu_locale, status));
     126         847 :     icu::UnicodeString pattern;
     127         847 :     if (U_SUCCESS(status))
     128        1694 :       pattern = generator->getBestPattern(skeleton, status);
     129             : 
     130         847 :     date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
     131         847 :     if (U_SUCCESS(status)) {
     132         847 :       date_format->adoptCalendar(calendar);
     133             :     }
     134             :   }
     135             : 
     136         847 :   if (U_FAILURE(status)) {
     137           0 :     delete calendar;
     138           0 :     delete date_format;
     139             :     date_format = nullptr;
     140             :   }
     141             : 
     142         847 :   return date_format;
     143             : }
     144             : 
     145        1694 : void SetResolvedDateSettings(Isolate* isolate, const icu::Locale& icu_locale,
     146             :                              icu::SimpleDateFormat* date_format,
     147             :                              Handle<JSObject> resolved) {
     148             :   Factory* factory = isolate->factory();
     149         847 :   UErrorCode status = U_ZERO_ERROR;
     150             :   icu::UnicodeString pattern;
     151         847 :   date_format->toPattern(pattern);
     152             :   JSObject::SetProperty(
     153             :       resolved, factory->intl_pattern_symbol(),
     154             :       factory
     155             :           ->NewStringFromTwoByte(Vector<const uint16_t>(
     156             :               reinterpret_cast<const uint16_t*>(pattern.getBuffer()),
     157        1694 :               pattern.length()))
     158             :           .ToHandleChecked(),
     159        1694 :       LanguageMode::kSloppy)
     160         847 :       .Assert();
     161             : 
     162             :   // Set time zone and calendar.
     163         847 :   const icu::Calendar* calendar = date_format->getCalendar();
     164             :   // getType() returns legacy calendar type name instead of LDML/BCP47 calendar
     165             :   // key values. intl.js maps them to BCP47 values for key "ca".
     166             :   // TODO(jshin): Consider doing it here, instead.
     167         847 :   const char* calendar_name = calendar->getType();
     168             :   JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("calendar"),
     169             :                         factory->NewStringFromAsciiChecked(calendar_name),
     170        2541 :                         LanguageMode::kSloppy)
     171         847 :       .Assert();
     172             : 
     173         847 :   const icu::TimeZone& tz = calendar->getTimeZone();
     174         847 :   icu::UnicodeString time_zone;
     175             :   tz.getID(time_zone);
     176             : 
     177         847 :   icu::UnicodeString canonical_time_zone;
     178         847 :   icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status);
     179         847 :   if (U_SUCCESS(status)) {
     180             :     // In CLDR (http://unicode.org/cldr/trac/ticket/9943), Etc/UTC is made
     181             :     // a separate timezone ID from Etc/GMT even though they're still the same
     182             :     // timezone. We'd not have "Etc/GMT" here because we canonicalize it and
     183             :     // other GMT-variants to "UTC" in intl.js and "UTC" is turned to "Etc/UTC"
     184             :     // by ICU before getting here.
     185             :     // TODO(jshin): Figure out the cause of crbug.com/719609 and re-enable
     186             :     //  DCHECK(canonical_time_zone != UNICODE_STRING_SIMPLE("Etc/GMT")) .
     187        3324 :     if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/UTC") ||
     188        2413 :         canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) {
     189             :       JSObject::SetProperty(
     190             :           resolved, factory->NewStringFromStaticChars("timeZone"),
     191         192 :           factory->NewStringFromStaticChars("UTC"), LanguageMode::kSloppy)
     192          64 :           .Assert();
     193             :     } else {
     194             :       JSObject::SetProperty(resolved,
     195             :                             factory->NewStringFromStaticChars("timeZone"),
     196             :                             factory
     197             :                                 ->NewStringFromTwoByte(Vector<const uint16_t>(
     198             :                                     reinterpret_cast<const uint16_t*>(
     199             :                                         canonical_time_zone.getBuffer()),
     200        1566 :                                     canonical_time_zone.length()))
     201             :                                 .ToHandleChecked(),
     202        2349 :                             LanguageMode::kSloppy)
     203         783 :           .Assert();
     204             :     }
     205             :   }
     206             : 
     207             :   // Ugly hack. ICU doesn't expose numbering system in any way, so we have
     208             :   // to assume that for given locale NumberingSystem constructor produces the
     209             :   // same digits as NumberFormat/Calendar would.
     210         847 :   status = U_ZERO_ERROR;
     211             :   icu::NumberingSystem* numbering_system =
     212         847 :       icu::NumberingSystem::createInstance(icu_locale, status);
     213         847 :   if (U_SUCCESS(status)) {
     214         847 :     const char* ns = numbering_system->getName();
     215             :     JSObject::SetProperty(
     216             :         resolved, factory->NewStringFromStaticChars("numberingSystem"),
     217        2541 :         factory->NewStringFromAsciiChecked(ns), LanguageMode::kSloppy)
     218         847 :         .Assert();
     219             :   } else {
     220             :     JSObject::SetProperty(resolved,
     221             :                           factory->NewStringFromStaticChars("numberingSystem"),
     222           0 :                           factory->undefined_value(), LanguageMode::kSloppy)
     223           0 :         .Assert();
     224             :   }
     225         847 :   delete numbering_system;
     226             : 
     227             :   // Set the locale
     228             :   char result[ULOC_FULLNAME_CAPACITY];
     229         847 :   status = U_ZERO_ERROR;
     230             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     231         847 :                      FALSE, &status);
     232         847 :   if (U_SUCCESS(status)) {
     233             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     234             :                           factory->NewStringFromAsciiChecked(result),
     235        2541 :                           LanguageMode::kSloppy)
     236         847 :         .Assert();
     237             :   } else {
     238             :     // This would never happen, since we got the locale from ICU.
     239             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     240             :                           factory->NewStringFromStaticChars("und"),
     241           0 :                           LanguageMode::kSloppy)
     242           0 :         .Assert();
     243         847 :   }
     244         847 : }
     245             : 
     246         636 : void SetNumericSettings(Isolate* isolate, icu::DecimalFormat* number_format,
     247             :                         Handle<JSObject> options) {
     248             :   int32_t digits;
     249         636 :   if (ExtractIntegerSetting(isolate, options, "minimumIntegerDigits",
     250             :                             &digits)) {
     251         636 :     number_format->setMinimumIntegerDigits(digits);
     252             :   }
     253             : 
     254         636 :   if (ExtractIntegerSetting(isolate, options, "minimumFractionDigits",
     255             :                             &digits)) {
     256         636 :     number_format->setMinimumFractionDigits(digits);
     257             :   }
     258             : 
     259         636 :   if (ExtractIntegerSetting(isolate, options, "maximumFractionDigits",
     260             :                             &digits)) {
     261         636 :     number_format->setMaximumFractionDigits(digits);
     262             :   }
     263             : 
     264             :   bool significant_digits_used = false;
     265         636 :   if (ExtractIntegerSetting(isolate, options, "minimumSignificantDigits",
     266             :                             &digits)) {
     267          27 :     number_format->setMinimumSignificantDigits(digits);
     268             :     significant_digits_used = true;
     269             :   }
     270             : 
     271         636 :   if (ExtractIntegerSetting(isolate, options, "maximumSignificantDigits",
     272             :                             &digits)) {
     273          27 :     number_format->setMaximumSignificantDigits(digits);
     274             :     significant_digits_used = true;
     275             :   }
     276             : 
     277         636 :   number_format->setSignificantDigitsUsed(significant_digits_used);
     278             : 
     279         636 :   number_format->setRoundingMode(icu::DecimalFormat::kRoundHalfUp);
     280         636 : }
     281             : 
     282         627 : icu::DecimalFormat* CreateICUNumberFormat(Isolate* isolate,
     283             :                                           const icu::Locale& icu_locale,
     284             :                                           Handle<JSObject> options) {
     285             :   // Make formatter from options. Numbering system is added
     286             :   // to the locale as Unicode extension (if it was specified at all).
     287         627 :   UErrorCode status = U_ZERO_ERROR;
     288             :   icu::DecimalFormat* number_format = nullptr;
     289             :   icu::UnicodeString style;
     290         627 :   icu::UnicodeString currency;
     291         627 :   if (ExtractStringSetting(isolate, options, "style", &style)) {
     292        1254 :     if (style == UNICODE_STRING_SIMPLE("currency")) {
     293             :       icu::UnicodeString display;
     294         117 :       ExtractStringSetting(isolate, options, "currency", &currency);
     295         117 :       ExtractStringSetting(isolate, options, "currencyDisplay", &display);
     296             : 
     297             : #if (U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM <= 6)
     298             :       icu::NumberFormat::EStyles format_style;
     299             :       if (display == UNICODE_STRING_SIMPLE("code")) {
     300             :         format_style = icu::NumberFormat::kIsoCurrencyStyle;
     301             :       } else if (display == UNICODE_STRING_SIMPLE("name")) {
     302             :         format_style = icu::NumberFormat::kPluralCurrencyStyle;
     303             :       } else {
     304             :         format_style = icu::NumberFormat::kCurrencyStyle;
     305             :       }
     306             : #else  // ICU version is 4.8 or above (we ignore versions below 4.0).
     307             :       UNumberFormatStyle format_style;
     308         234 :       if (display == UNICODE_STRING_SIMPLE("code")) {
     309             :         format_style = UNUM_CURRENCY_ISO;
     310         180 :       } else if (display == UNICODE_STRING_SIMPLE("name")) {
     311             :         format_style = UNUM_CURRENCY_PLURAL;
     312             :       } else {
     313             :         format_style = UNUM_CURRENCY;
     314             :       }
     315             : #endif
     316             : 
     317             :       number_format = static_cast<icu::DecimalFormat*>(
     318         117 :           icu::NumberFormat::createInstance(icu_locale, format_style, status));
     319             : 
     320         117 :       if (U_FAILURE(status)) {
     321           0 :         delete number_format;
     322           0 :         return nullptr;
     323         117 :       }
     324        1020 :     } else if (style == UNICODE_STRING_SIMPLE("percent")) {
     325             :       number_format = static_cast<icu::DecimalFormat*>(
     326          36 :           icu::NumberFormat::createPercentInstance(icu_locale, status));
     327          36 :       if (U_FAILURE(status)) {
     328           0 :         delete number_format;
     329             :         return nullptr;
     330             :       }
     331             :       // Make sure 1.1% doesn't go into 2%.
     332          36 :       number_format->setMinimumFractionDigits(1);
     333             :     } else {
     334             :       // Make a decimal instance by default.
     335             :       number_format = static_cast<icu::DecimalFormat*>(
     336         474 :           icu::NumberFormat::createInstance(icu_locale, status));
     337             :     }
     338             :   }
     339             : 
     340         627 :   if (U_FAILURE(status)) {
     341          18 :     delete number_format;
     342             :     return nullptr;
     343             :   }
     344             : 
     345             :   // Set all options.
     346        1218 :   if (!currency.isEmpty()) {
     347         234 :     number_format->setCurrency(currency.getBuffer(), status);
     348             :   }
     349             : 
     350         609 :   SetNumericSettings(isolate, number_format, options);
     351             : 
     352             :   bool grouping;
     353         609 :   if (ExtractBooleanSetting(isolate, options, "useGrouping", &grouping)) {
     354         609 :     number_format->setGroupingUsed(grouping);
     355             :   }
     356             : 
     357        1236 :   return number_format;
     358             : }
     359             : 
     360        1272 : void SetResolvedNumericSettings(Isolate* isolate, const icu::Locale& icu_locale,
     361             :                                 icu::DecimalFormat* number_format,
     362             :                                 Handle<JSObject> resolved) {
     363             :   Factory* factory = isolate->factory();
     364             : 
     365             :   JSObject::SetProperty(
     366             :       resolved, factory->NewStringFromStaticChars("minimumIntegerDigits"),
     367             :       factory->NewNumberFromInt(number_format->getMinimumIntegerDigits()),
     368        1272 :       LanguageMode::kSloppy)
     369         636 :       .Assert();
     370             : 
     371             :   JSObject::SetProperty(
     372             :       resolved, factory->NewStringFromStaticChars("minimumFractionDigits"),
     373             :       factory->NewNumberFromInt(number_format->getMinimumFractionDigits()),
     374        1272 :       LanguageMode::kSloppy)
     375         636 :       .Assert();
     376             : 
     377             :   JSObject::SetProperty(
     378             :       resolved, factory->NewStringFromStaticChars("maximumFractionDigits"),
     379             :       factory->NewNumberFromInt(number_format->getMaximumFractionDigits()),
     380        1272 :       LanguageMode::kSloppy)
     381         636 :       .Assert();
     382             : 
     383             :   Handle<String> key =
     384         636 :       factory->NewStringFromStaticChars("minimumSignificantDigits");
     385         636 :   Maybe<bool> maybe = JSReceiver::HasOwnProperty(resolved, key);
     386         636 :   CHECK(maybe.IsJust());
     387         636 :   if (maybe.FromJust()) {
     388             :     JSObject::SetProperty(
     389             :         resolved, factory->NewStringFromStaticChars("minimumSignificantDigits"),
     390             :         factory->NewNumberFromInt(number_format->getMinimumSignificantDigits()),
     391          54 :         LanguageMode::kSloppy)
     392          27 :         .Assert();
     393             :   }
     394             : 
     395         636 :   key = factory->NewStringFromStaticChars("maximumSignificantDigits");
     396         636 :   maybe = JSReceiver::HasOwnProperty(resolved, key);
     397         636 :   CHECK(maybe.IsJust());
     398         636 :   if (maybe.FromJust()) {
     399             :     JSObject::SetProperty(
     400             :         resolved, factory->NewStringFromStaticChars("maximumSignificantDigits"),
     401             :         factory->NewNumberFromInt(number_format->getMaximumSignificantDigits()),
     402          54 :         LanguageMode::kSloppy)
     403          27 :         .Assert();
     404             :   }
     405             : 
     406             :   // Set the locale
     407             :   char result[ULOC_FULLNAME_CAPACITY];
     408         636 :   UErrorCode status = U_ZERO_ERROR;
     409             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     410         636 :                      FALSE, &status);
     411         636 :   if (U_SUCCESS(status)) {
     412             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     413             :                           factory->NewStringFromAsciiChecked(result),
     414        1908 :                           LanguageMode::kSloppy)
     415         636 :         .Assert();
     416             :   } else {
     417             :     // This would never happen, since we got the locale from ICU.
     418             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     419             :                           factory->NewStringFromStaticChars("und"),
     420           0 :                           LanguageMode::kSloppy)
     421           0 :         .Assert();
     422             :   }
     423         636 : }
     424             : 
     425         609 : void SetResolvedNumberSettings(Isolate* isolate, const icu::Locale& icu_locale,
     426             :                                icu::DecimalFormat* number_format,
     427             :                                Handle<JSObject> resolved) {
     428             :   Factory* factory = isolate->factory();
     429             : 
     430             :   // Set resolved currency code in options.currency if not empty.
     431         609 :   icu::UnicodeString currency(number_format->getCurrency());
     432        1218 :   if (!currency.isEmpty()) {
     433             :     JSObject::SetProperty(
     434             :         resolved, factory->NewStringFromStaticChars("currency"),
     435             :         factory
     436             :             ->NewStringFromTwoByte(Vector<const uint16_t>(
     437             :                 reinterpret_cast<const uint16_t*>(currency.getBuffer()),
     438         234 :                 currency.length()))
     439             :             .ToHandleChecked(),
     440         351 :         LanguageMode::kSloppy)
     441         117 :         .Assert();
     442             :   }
     443             : 
     444             :   // Ugly hack. ICU doesn't expose numbering system in any way, so we have
     445             :   // to assume that for given locale NumberingSystem constructor produces the
     446             :   // same digits as NumberFormat/Calendar would.
     447         609 :   UErrorCode status = U_ZERO_ERROR;
     448             :   icu::NumberingSystem* numbering_system =
     449         609 :       icu::NumberingSystem::createInstance(icu_locale, status);
     450         609 :   if (U_SUCCESS(status)) {
     451         609 :     const char* ns = numbering_system->getName();
     452             :     JSObject::SetProperty(
     453             :         resolved, factory->NewStringFromStaticChars("numberingSystem"),
     454        1827 :         factory->NewStringFromAsciiChecked(ns), LanguageMode::kSloppy)
     455         609 :         .Assert();
     456             :   } else {
     457             :     JSObject::SetProperty(resolved,
     458             :                           factory->NewStringFromStaticChars("numberingSystem"),
     459           0 :                           factory->undefined_value(), LanguageMode::kSloppy)
     460           0 :         .Assert();
     461             :   }
     462         609 :   delete numbering_system;
     463             : 
     464             :   JSObject::SetProperty(resolved,
     465             :                         factory->NewStringFromStaticChars("useGrouping"),
     466         609 :                         factory->ToBoolean(number_format->isGroupingUsed()),
     467        1218 :                         LanguageMode::kSloppy)
     468         609 :       .Assert();
     469             : 
     470         609 :   SetResolvedNumericSettings(isolate, icu_locale, number_format, resolved);
     471         609 : }
     472             : 
     473        9716 : icu::Collator* CreateICUCollator(Isolate* isolate,
     474             :                                  const icu::Locale& icu_locale,
     475             :                                  Handle<JSObject> options) {
     476             :   // Make collator from options.
     477             :   icu::Collator* collator = nullptr;
     478        9716 :   UErrorCode status = U_ZERO_ERROR;
     479        9716 :   collator = icu::Collator::createInstance(icu_locale, status);
     480             : 
     481        9716 :   if (U_FAILURE(status)) {
     482           0 :     delete collator;
     483             :     return nullptr;
     484             :   }
     485             : 
     486             :   // Set flags first, and then override them with sensitivity if necessary.
     487             :   bool numeric;
     488        9716 :   if (ExtractBooleanSetting(isolate, options, "numeric", &numeric)) {
     489             :     collator->setAttribute(UCOL_NUMERIC_COLLATION, numeric ? UCOL_ON : UCOL_OFF,
     490           0 :                            status);
     491             :   }
     492             : 
     493             :   // Normalization is always on, by the spec. We are free to optimize
     494             :   // if the strings are already normalized (but we don't have a way to tell
     495             :   // that right now).
     496        9716 :   collator->setAttribute(UCOL_NORMALIZATION_MODE, UCOL_ON, status);
     497             : 
     498             :   icu::UnicodeString case_first;
     499        9716 :   if (ExtractStringSetting(isolate, options, "caseFirst", &case_first)) {
     500         432 :     if (case_first == UNICODE_STRING_SIMPLE("upper")) {
     501         216 :       collator->setAttribute(UCOL_CASE_FIRST, UCOL_UPPER_FIRST, status);
     502           0 :     } else if (case_first == UNICODE_STRING_SIMPLE("lower")) {
     503           0 :       collator->setAttribute(UCOL_CASE_FIRST, UCOL_LOWER_FIRST, status);
     504             :     } else {
     505             :       // Default (false/off).
     506           0 :       collator->setAttribute(UCOL_CASE_FIRST, UCOL_OFF, status);
     507             :     }
     508             :   }
     509             : 
     510        9716 :   icu::UnicodeString sensitivity;
     511        9716 :   if (ExtractStringSetting(isolate, options, "sensitivity", &sensitivity)) {
     512       19414 :     if (sensitivity == UNICODE_STRING_SIMPLE("base")) {
     513           0 :       collator->setStrength(icu::Collator::PRIMARY);
     514       19414 :     } else if (sensitivity == UNICODE_STRING_SIMPLE("accent")) {
     515           0 :       collator->setStrength(icu::Collator::SECONDARY);
     516       19414 :     } else if (sensitivity == UNICODE_STRING_SIMPLE("case")) {
     517           0 :       collator->setStrength(icu::Collator::PRIMARY);
     518           0 :       collator->setAttribute(UCOL_CASE_LEVEL, UCOL_ON, status);
     519             :     } else {
     520             :       // variant (default)
     521        9707 :       collator->setStrength(icu::Collator::TERTIARY);
     522             :     }
     523             :   }
     524             : 
     525             :   bool ignore;
     526        9716 :   if (ExtractBooleanSetting(isolate, options, "ignorePunctuation", &ignore)) {
     527        9716 :     if (ignore) {
     528           0 :       collator->setAttribute(UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, status);
     529             :     }
     530             :   }
     531             : 
     532        9716 :   return collator;
     533             : }
     534             : 
     535        9716 : void SetResolvedCollatorSettings(Isolate* isolate,
     536        9716 :                                  const icu::Locale& icu_locale,
     537             :                                  icu::Collator* collator,
     538             :                                  Handle<JSObject> resolved) {
     539             :   Factory* factory = isolate->factory();
     540        9716 :   UErrorCode status = U_ZERO_ERROR;
     541             : 
     542             :   JSObject::SetProperty(
     543             :       resolved, factory->NewStringFromStaticChars("numeric"),
     544             :       factory->ToBoolean(
     545        9716 :           collator->getAttribute(UCOL_NUMERIC_COLLATION, status) == UCOL_ON),
     546       19432 :       LanguageMode::kSloppy)
     547        9716 :       .Assert();
     548             : 
     549        9716 :   switch (collator->getAttribute(UCOL_CASE_FIRST, status)) {
     550             :     case UCOL_LOWER_FIRST:
     551             :       JSObject::SetProperty(
     552             :           resolved, factory->NewStringFromStaticChars("caseFirst"),
     553           0 :           factory->NewStringFromStaticChars("lower"), LanguageMode::kSloppy)
     554           0 :           .Assert();
     555           0 :       break;
     556             :     case UCOL_UPPER_FIRST:
     557             :       JSObject::SetProperty(
     558             :           resolved, factory->NewStringFromStaticChars("caseFirst"),
     559         648 :           factory->NewStringFromStaticChars("upper"), LanguageMode::kSloppy)
     560         216 :           .Assert();
     561         216 :       break;
     562             :     default:
     563             :       JSObject::SetProperty(
     564             :           resolved, factory->NewStringFromStaticChars("caseFirst"),
     565       28500 :           factory->NewStringFromStaticChars("false"), LanguageMode::kSloppy)
     566        9500 :           .Assert();
     567             :   }
     568             : 
     569        9716 :   switch (collator->getAttribute(UCOL_STRENGTH, status)) {
     570             :     case UCOL_PRIMARY: {
     571             :       JSObject::SetProperty(
     572             :           resolved, factory->NewStringFromStaticChars("strength"),
     573           0 :           factory->NewStringFromStaticChars("primary"), LanguageMode::kSloppy)
     574           0 :           .Assert();
     575             : 
     576             :       // case level: true + s1 -> case, s1 -> base.
     577           0 :       if (UCOL_ON == collator->getAttribute(UCOL_CASE_LEVEL, status)) {
     578             :         JSObject::SetProperty(
     579             :             resolved, factory->NewStringFromStaticChars("sensitivity"),
     580           0 :             factory->NewStringFromStaticChars("case"), LanguageMode::kSloppy)
     581           0 :             .Assert();
     582             :       } else {
     583             :         JSObject::SetProperty(
     584             :             resolved, factory->NewStringFromStaticChars("sensitivity"),
     585           0 :             factory->NewStringFromStaticChars("base"), LanguageMode::kSloppy)
     586           0 :             .Assert();
     587             :       }
     588             :       break;
     589             :     }
     590             :     case UCOL_SECONDARY:
     591             :       JSObject::SetProperty(
     592             :           resolved, factory->NewStringFromStaticChars("strength"),
     593           0 :           factory->NewStringFromStaticChars("secondary"), LanguageMode::kSloppy)
     594           0 :           .Assert();
     595             :       JSObject::SetProperty(
     596             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     597           0 :           factory->NewStringFromStaticChars("accent"), LanguageMode::kSloppy)
     598           0 :           .Assert();
     599           0 :       break;
     600             :     case UCOL_TERTIARY:
     601             :       JSObject::SetProperty(
     602             :           resolved, factory->NewStringFromStaticChars("strength"),
     603       29148 :           factory->NewStringFromStaticChars("tertiary"), LanguageMode::kSloppy)
     604        9716 :           .Assert();
     605             :       JSObject::SetProperty(
     606             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     607       29148 :           factory->NewStringFromStaticChars("variant"), LanguageMode::kSloppy)
     608        9716 :           .Assert();
     609        9716 :       break;
     610             :     case UCOL_QUATERNARY:
     611             :       // We shouldn't get quaternary and identical from ICU, but if we do
     612             :       // put them into variant.
     613             :       JSObject::SetProperty(resolved,
     614             :                             factory->NewStringFromStaticChars("strength"),
     615             :                             factory->NewStringFromStaticChars("quaternary"),
     616           0 :                             LanguageMode::kSloppy)
     617           0 :           .Assert();
     618             :       JSObject::SetProperty(
     619             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     620           0 :           factory->NewStringFromStaticChars("variant"), LanguageMode::kSloppy)
     621           0 :           .Assert();
     622           0 :       break;
     623             :     default:
     624             :       JSObject::SetProperty(
     625             :           resolved, factory->NewStringFromStaticChars("strength"),
     626           0 :           factory->NewStringFromStaticChars("identical"), LanguageMode::kSloppy)
     627           0 :           .Assert();
     628             :       JSObject::SetProperty(
     629             :           resolved, factory->NewStringFromStaticChars("sensitivity"),
     630           0 :           factory->NewStringFromStaticChars("variant"), LanguageMode::kSloppy)
     631           0 :           .Assert();
     632             :   }
     633             : 
     634             :   JSObject::SetProperty(
     635             :       resolved, factory->NewStringFromStaticChars("ignorePunctuation"),
     636             :       factory->ToBoolean(collator->getAttribute(UCOL_ALTERNATE_HANDLING,
     637        9716 :                                                 status) == UCOL_SHIFTED),
     638       19432 :       LanguageMode::kSloppy)
     639        9716 :       .Assert();
     640             : 
     641             :   // Set the locale
     642             :   char result[ULOC_FULLNAME_CAPACITY];
     643        9716 :   status = U_ZERO_ERROR;
     644             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     645        9716 :                      FALSE, &status);
     646        9716 :   if (U_SUCCESS(status)) {
     647             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     648             :                           factory->NewStringFromAsciiChecked(result),
     649       29148 :                           LanguageMode::kSloppy)
     650        9716 :         .Assert();
     651             :   } else {
     652             :     // This would never happen, since we got the locale from ICU.
     653             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     654             :                           factory->NewStringFromStaticChars("und"),
     655           0 :                           LanguageMode::kSloppy)
     656           0 :         .Assert();
     657             :   }
     658        9716 : }
     659             : 
     660          27 : bool CreateICUPluralRules(Isolate* isolate, const icu::Locale& icu_locale,
     661             :                           Handle<JSObject> options, icu::PluralRules** pl,
     662             :                           icu::DecimalFormat** nf) {
     663             :   // Make formatter from options. Numbering system is added
     664             :   // to the locale as Unicode extension (if it was specified at all).
     665          27 :   UErrorCode status = U_ZERO_ERROR;
     666             : 
     667             :   UPluralType type = UPLURAL_TYPE_CARDINAL;
     668             : 
     669             :   icu::UnicodeString type_string;
     670          27 :   if (ExtractStringSetting(isolate, options, "type", &type_string)) {
     671          54 :     if (type_string == UNICODE_STRING_SIMPLE("ordinal")) {
     672             :       type = UPLURAL_TYPE_ORDINAL;
     673             :     } else {
     674          36 :       CHECK(type_string == UNICODE_STRING_SIMPLE("cardinal"));
     675             :     }
     676             :   }
     677             : 
     678             :   icu::PluralRules* plural_rules =
     679          27 :       icu::PluralRules::forLocale(icu_locale, type, status);
     680             : 
     681          27 :   if (U_FAILURE(status)) {
     682           0 :     delete plural_rules;
     683             :     return false;
     684             :   }
     685             : 
     686             :   icu::DecimalFormat* number_format = static_cast<icu::DecimalFormat*>(
     687          27 :       icu::NumberFormat::createInstance(icu_locale, UNUM_DECIMAL, status));
     688             : 
     689          27 :   if (U_FAILURE(status)) {
     690           0 :     delete plural_rules;
     691           0 :     delete number_format;
     692             :     return false;
     693             :   }
     694             : 
     695          27 :   *pl = plural_rules;
     696          27 :   *nf = number_format;
     697             : 
     698          27 :   SetNumericSettings(isolate, number_format, options);
     699             : 
     700             :   // Set rounding mode.
     701             : 
     702          27 :   return true;
     703             : }
     704             : 
     705          27 : bool SetResolvedPluralRulesSettings(Isolate* isolate,
     706             :                                     const icu::Locale& icu_locale,
     707             :                                     icu::PluralRules* plural_rules,
     708             :                                     icu::DecimalFormat* number_format,
     709             :                                     Handle<JSObject> resolved) {
     710          27 :   SetResolvedNumericSettings(isolate, icu_locale, number_format, resolved);
     711             : 
     712             :   Factory* factory = isolate->factory();
     713             : 
     714             :   Handle<JSObject> pluralCategories = Handle<JSObject>::cast(
     715             :       JSObject::GetProperty(
     716          54 :           resolved, factory->NewStringFromStaticChars("pluralCategories"))
     717          54 :           .ToHandleChecked());
     718             : 
     719          27 :   UErrorCode status = U_ZERO_ERROR;
     720             :   std::unique_ptr<icu::StringEnumeration> categories(
     721          27 :       plural_rules->getKeywords(status));
     722          27 :   if (U_FAILURE(status)) return false;
     723             : 
     724          27 :   if (U_FAILURE(status)) return false;
     725             : 
     726         108 :   for (int32_t i = 0;; i++) {
     727         135 :     const icu::UnicodeString* category = categories->snext(status);
     728         162 :     if (U_FAILURE(status)) return false;
     729         135 :     if (category == nullptr) return true;
     730             : 
     731             :     std::string keyword;
     732             :     Handle<String> value = factory->NewStringFromAsciiChecked(
     733         216 :         category->toUTF8String(keyword).data());
     734             : 
     735         216 :     LookupIterator it(isolate, pluralCategories, i, LookupIterator::OWN);
     736             :     JSObject::DefineOwnPropertyIgnoreAttributes(&it, value,
     737         108 :                                                 PropertyAttributes::NONE)
     738         216 :         .ToHandleChecked();
     739         108 :   }
     740             : }
     741             : 
     742         115 : icu::BreakIterator* CreateICUBreakIterator(Isolate* isolate,
     743             :                                            const icu::Locale& icu_locale,
     744             :                                            Handle<JSObject> options) {
     745         115 :   UErrorCode status = U_ZERO_ERROR;
     746             :   icu::BreakIterator* break_iterator = nullptr;
     747             :   icu::UnicodeString type;
     748         115 :   if (!ExtractStringSetting(isolate, options, "type", &type)) return nullptr;
     749             : 
     750         230 :   if (type == UNICODE_STRING_SIMPLE("character")) {
     751             :     break_iterator =
     752           0 :         icu::BreakIterator::createCharacterInstance(icu_locale, status);
     753         230 :   } else if (type == UNICODE_STRING_SIMPLE("sentence")) {
     754             :     break_iterator =
     755           0 :         icu::BreakIterator::createSentenceInstance(icu_locale, status);
     756         230 :   } else if (type == UNICODE_STRING_SIMPLE("line")) {
     757           0 :     break_iterator = icu::BreakIterator::createLineInstance(icu_locale, status);
     758             :   } else {
     759             :     // Defualt is word iterator.
     760         115 :     break_iterator = icu::BreakIterator::createWordInstance(icu_locale, status);
     761             :   }
     762             : 
     763         115 :   if (U_FAILURE(status)) {
     764           0 :     delete break_iterator;
     765             :     return nullptr;
     766             :   }
     767             : 
     768         115 :   isolate->CountUsage(v8::Isolate::UseCounterFeature::kBreakIterator);
     769             : 
     770         115 :   return break_iterator;
     771             : }
     772             : 
     773         115 : void SetResolvedBreakIteratorSettings(Isolate* isolate,
     774         115 :                                       const icu::Locale& icu_locale,
     775             :                                       icu::BreakIterator* break_iterator,
     776             :                                       Handle<JSObject> resolved) {
     777             :   Factory* factory = isolate->factory();
     778         115 :   UErrorCode status = U_ZERO_ERROR;
     779             : 
     780             :   // Set the locale
     781             :   char result[ULOC_FULLNAME_CAPACITY];
     782             :   status = U_ZERO_ERROR;
     783             :   uloc_toLanguageTag(icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY,
     784         115 :                      FALSE, &status);
     785         115 :   if (U_SUCCESS(status)) {
     786             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     787             :                           factory->NewStringFromAsciiChecked(result),
     788         345 :                           LanguageMode::kSloppy)
     789         115 :         .Assert();
     790             :   } else {
     791             :     // This would never happen, since we got the locale from ICU.
     792             :     JSObject::SetProperty(resolved, factory->NewStringFromStaticChars("locale"),
     793             :                           factory->NewStringFromStaticChars("und"),
     794           0 :                           LanguageMode::kSloppy)
     795           0 :         .Assert();
     796             :   }
     797         115 : }
     798             : }  // namespace
     799             : 
     800             : // static
     801         847 : icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat(
     802             :     Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
     803             :     Handle<JSObject> resolved) {
     804             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     805             :   // Convert BCP47 into ICU locale format.
     806         847 :   UErrorCode status = U_ZERO_ERROR;
     807         847 :   icu::Locale icu_locale;
     808             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     809         847 :   int icu_length = 0;
     810        1694 :   v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale));
     811         847 :   if (bcp47_locale.length() != 0) {
     812         847 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     813         847 :                         &icu_length, &status);
     814         847 :     if (U_FAILURE(status) || icu_length == 0) {
     815             :       return nullptr;
     816             :     }
     817         847 :     icu_locale = icu::Locale(icu_result);
     818             :   }
     819             : 
     820             :   icu::SimpleDateFormat* date_format =
     821         847 :       CreateICUDateFormat(isolate, icu_locale, options);
     822         847 :   if (!date_format) {
     823             :     // Remove extensions and try again.
     824           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     825           0 :     date_format = CreateICUDateFormat(isolate, no_extension_locale, options);
     826             : 
     827           0 :     if (!date_format) {
     828           0 :       FATAL("Failed to create ICU date format, are ICU data files missing?");
     829             :     }
     830             : 
     831             :     // Set resolved settings (pattern, numbering system, calendar).
     832             :     SetResolvedDateSettings(isolate, no_extension_locale, date_format,
     833           0 :                             resolved);
     834             :   } else {
     835         847 :     SetResolvedDateSettings(isolate, icu_locale, date_format, resolved);
     836             :   }
     837             : 
     838        1694 :   return date_format;
     839             : }
     840             : 
     841         436 : icu::SimpleDateFormat* DateFormat::UnpackDateFormat(Isolate* isolate,
     842             :                                                     Handle<JSObject> obj) {
     843         436 :   return reinterpret_cast<icu::SimpleDateFormat*>(obj->GetEmbedderField(0));
     844             : }
     845             : 
     846         144 : void DateFormat::DeleteDateFormat(const v8::WeakCallbackInfo<void>& data) {
     847          72 :   delete reinterpret_cast<icu::SimpleDateFormat*>(data.GetInternalField(0));
     848          72 :   GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
     849          72 : }
     850             : 
     851         609 : icu::DecimalFormat* NumberFormat::InitializeNumberFormat(
     852             :     Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
     853             :     Handle<JSObject> resolved) {
     854             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     855             : 
     856             :   // Convert BCP47 into ICU locale format.
     857         609 :   UErrorCode status = U_ZERO_ERROR;
     858         609 :   icu::Locale icu_locale;
     859             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     860         609 :   int icu_length = 0;
     861        1218 :   v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale));
     862         609 :   if (bcp47_locale.length() != 0) {
     863         609 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     864         609 :                         &icu_length, &status);
     865         609 :     if (U_FAILURE(status) || icu_length == 0) {
     866             :       return nullptr;
     867             :     }
     868         609 :     icu_locale = icu::Locale(icu_result);
     869             :   }
     870             : 
     871             :   icu::DecimalFormat* number_format =
     872         609 :       CreateICUNumberFormat(isolate, icu_locale, options);
     873         609 :   if (!number_format) {
     874             :     // Remove extensions and try again.
     875          18 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     876             :     number_format =
     877          18 :         CreateICUNumberFormat(isolate, no_extension_locale, options);
     878             : 
     879          18 :     if (!number_format) {
     880           0 :       FATAL("Failed to create ICU number format, are ICU data files missing?");
     881             :     }
     882             : 
     883             :     // Set resolved settings (pattern, numbering system).
     884             :     SetResolvedNumberSettings(isolate, no_extension_locale, number_format,
     885          18 :                               resolved);
     886             :   } else {
     887         591 :     SetResolvedNumberSettings(isolate, icu_locale, number_format, resolved);
     888             :   }
     889             : 
     890        1218 :   return number_format;
     891             : }
     892             : 
     893        2243 : icu::DecimalFormat* NumberFormat::UnpackNumberFormat(Isolate* isolate,
     894             :                                                      Handle<JSObject> obj) {
     895        2243 :   return reinterpret_cast<icu::DecimalFormat*>(obj->GetEmbedderField(0));
     896             : }
     897             : 
     898          80 : void NumberFormat::DeleteNumberFormat(const v8::WeakCallbackInfo<void>& data) {
     899          40 :   delete reinterpret_cast<icu::DecimalFormat*>(data.GetInternalField(0));
     900          40 :   GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
     901          40 : }
     902             : 
     903        9716 : icu::Collator* Collator::InitializeCollator(Isolate* isolate,
     904             :                                             Handle<String> locale,
     905             :                                             Handle<JSObject> options,
     906             :                                             Handle<JSObject> resolved) {
     907             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     908             :   // Convert BCP47 into ICU locale format.
     909        9716 :   UErrorCode status = U_ZERO_ERROR;
     910        9716 :   icu::Locale icu_locale;
     911             :   char icu_result[ULOC_FULLNAME_CAPACITY];
     912        9716 :   int icu_length = 0;
     913       19432 :   v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale));
     914        9716 :   if (bcp47_locale.length() != 0) {
     915        9716 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
     916        9716 :                         &icu_length, &status);
     917        9716 :     if (U_FAILURE(status) || icu_length == 0) {
     918             :       return nullptr;
     919             :     }
     920        9716 :     icu_locale = icu::Locale(icu_result);
     921             :   }
     922             : 
     923        9716 :   icu::Collator* collator = CreateICUCollator(isolate, icu_locale, options);
     924        9716 :   if (!collator) {
     925             :     // Remove extensions and try again.
     926           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     927           0 :     collator = CreateICUCollator(isolate, no_extension_locale, options);
     928             : 
     929           0 :     if (!collator) {
     930           0 :       FATAL("Failed to create ICU collator, are ICU data files missing?");
     931             :     }
     932             : 
     933             :     // Set resolved settings (pattern, numbering system).
     934             :     SetResolvedCollatorSettings(isolate, no_extension_locale, collator,
     935           0 :                                 resolved);
     936             :   } else {
     937        9716 :     SetResolvedCollatorSettings(isolate, icu_locale, collator, resolved);
     938             :   }
     939             : 
     940       19432 :   return collator;
     941             : }
     942             : 
     943       91700 : icu::Collator* Collator::UnpackCollator(Isolate* isolate,
     944             :                                         Handle<JSObject> obj) {
     945       91700 :   return reinterpret_cast<icu::Collator*>(obj->GetEmbedderField(0));
     946             : }
     947             : 
     948        2152 : void Collator::DeleteCollator(const v8::WeakCallbackInfo<void>& data) {
     949        1076 :   delete reinterpret_cast<icu::Collator*>(data.GetInternalField(0));
     950        1076 :   GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
     951        1076 : }
     952             : 
     953          27 : bool PluralRules::InitializePluralRules(Isolate* isolate, Handle<String> locale,
     954             :                                         Handle<JSObject> options,
     955             :                                         Handle<JSObject> resolved,
     956             :                                         icu::PluralRules** plural_rules,
     957             :                                         icu::DecimalFormat** number_format) {
     958             :   // Convert BCP47 into ICU locale format.
     959          27 :   UErrorCode status = U_ZERO_ERROR;
     960          27 :   icu::Locale icu_locale;
     961             :   char locale_name[ULOC_FULLNAME_CAPACITY];
     962          27 :   int icu_length = 0;
     963             :   v8::String::Utf8Value bcp47_locale(reinterpret_cast<v8::Isolate*>(isolate),
     964          54 :                                      v8::Utils::ToLocal(locale));
     965          27 :   if (bcp47_locale.length() != 0) {
     966          27 :     uloc_forLanguageTag(*bcp47_locale, locale_name, ULOC_FULLNAME_CAPACITY,
     967          27 :                         &icu_length, &status);
     968          27 :     if (U_FAILURE(status) || icu_length == 0) {
     969             :       return false;
     970             :     }
     971          27 :     icu_locale = icu::Locale(locale_name);
     972             :   }
     973             : 
     974             :   bool success = CreateICUPluralRules(isolate, icu_locale, options,
     975          27 :                                       plural_rules, number_format);
     976          27 :   if (!success) {
     977             :     // Remove extensions and try again.
     978           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
     979             :     success = CreateICUPluralRules(isolate, no_extension_locale, options,
     980           0 :                                    plural_rules, number_format);
     981             : 
     982           0 :     if (!success) {
     983           0 :       FATAL("Failed to create ICU PluralRules, are ICU data files missing?");
     984             :     }
     985             : 
     986             :     // Set resolved settings (pattern, numbering system).
     987             :     success = SetResolvedPluralRulesSettings(
     988           0 :         isolate, no_extension_locale, *plural_rules, *number_format, resolved);
     989             :   } else {
     990             :     success = SetResolvedPluralRulesSettings(isolate, icu_locale, *plural_rules,
     991          27 :                                              *number_format, resolved);
     992             :   }
     993             : 
     994          54 :   return success;
     995             : }
     996             : 
     997         180 : icu::PluralRules* PluralRules::UnpackPluralRules(Isolate* isolate,
     998             :                                                  Handle<JSObject> obj) {
     999         180 :   return reinterpret_cast<icu::PluralRules*>(obj->GetEmbedderField(0));
    1000             : }
    1001             : 
    1002         180 : icu::DecimalFormat* PluralRules::UnpackNumberFormat(Isolate* isolate,
    1003             :                                                     Handle<JSObject> obj) {
    1004         180 :   return reinterpret_cast<icu::DecimalFormat*>(obj->GetEmbedderField(1));
    1005             : }
    1006             : 
    1007           0 : void PluralRules::DeletePluralRules(const v8::WeakCallbackInfo<void>& data) {
    1008           0 :   delete reinterpret_cast<icu::PluralRules*>(data.GetInternalField(0));
    1009           0 :   delete reinterpret_cast<icu::DecimalFormat*>(data.GetInternalField(1));
    1010           0 :   GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
    1011           0 : }
    1012             : 
    1013         115 : icu::BreakIterator* V8BreakIterator::InitializeBreakIterator(
    1014             :     Isolate* isolate, Handle<String> locale, Handle<JSObject> options,
    1015             :     Handle<JSObject> resolved) {
    1016             :   v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
    1017             :   // Convert BCP47 into ICU locale format.
    1018         115 :   UErrorCode status = U_ZERO_ERROR;
    1019         115 :   icu::Locale icu_locale;
    1020             :   char icu_result[ULOC_FULLNAME_CAPACITY];
    1021         115 :   int icu_length = 0;
    1022         230 :   v8::String::Utf8Value bcp47_locale(v8_isolate, v8::Utils::ToLocal(locale));
    1023         115 :   if (bcp47_locale.length() != 0) {
    1024         115 :     uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY,
    1025         115 :                         &icu_length, &status);
    1026         115 :     if (U_FAILURE(status) || icu_length == 0) {
    1027             :       return nullptr;
    1028             :     }
    1029         115 :     icu_locale = icu::Locale(icu_result);
    1030             :   }
    1031             : 
    1032             :   icu::BreakIterator* break_iterator =
    1033         115 :       CreateICUBreakIterator(isolate, icu_locale, options);
    1034         115 :   if (!break_iterator) {
    1035             :     // Remove extensions and try again.
    1036           0 :     icu::Locale no_extension_locale(icu_locale.getBaseName());
    1037             :     break_iterator =
    1038           0 :         CreateICUBreakIterator(isolate, no_extension_locale, options);
    1039             : 
    1040           0 :     if (!break_iterator) {
    1041           0 :       FATAL("Failed to create ICU break iterator, are ICU data files missing?");
    1042             :     }
    1043             : 
    1044             :     // Set resolved settings (locale).
    1045             :     SetResolvedBreakIteratorSettings(isolate, no_extension_locale,
    1046           0 :                                      break_iterator, resolved);
    1047             :   } else {
    1048             :     SetResolvedBreakIteratorSettings(isolate, icu_locale, break_iterator,
    1049         115 :                                      resolved);
    1050             :   }
    1051             : 
    1052         230 :   return break_iterator;
    1053             : }
    1054             : 
    1055         627 : icu::BreakIterator* V8BreakIterator::UnpackBreakIterator(Isolate* isolate,
    1056             :                                                          Handle<JSObject> obj) {
    1057         627 :   return reinterpret_cast<icu::BreakIterator*>(obj->GetEmbedderField(0));
    1058             : }
    1059             : 
    1060          11 : void V8BreakIterator::DeleteBreakIterator(
    1061          11 :     const v8::WeakCallbackInfo<void>& data) {
    1062          11 :   delete reinterpret_cast<icu::BreakIterator*>(data.GetInternalField(0));
    1063          11 :   delete reinterpret_cast<icu::UnicodeString*>(data.GetInternalField(1));
    1064          11 :   GlobalHandles::Destroy(reinterpret_cast<Object**>(data.GetParameter()));
    1065          11 : }
    1066             : 
    1067             : }  // namespace internal
    1068             : }  // namespace v8

Generated by: LCOV version 1.10