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