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", ¤cy);
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
|