OLD | NEW |
| (Empty) |
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/calendar.h" | |
32 #include "unicode/dtfmtsym.h" | |
33 #include "unicode/dtptngen.h" | |
34 #include "unicode/locid.h" | |
35 #include "unicode/numsys.h" | |
36 #include "unicode/smpdtfmt.h" | |
37 #include "unicode/timezone.h" | |
38 | |
39 namespace v8 { | |
40 namespace internal { | |
41 | |
42 namespace { | |
43 | |
44 icu::SimpleDateFormat* CreateICUDateFormat( | |
45 Isolate* isolate, | |
46 const icu::Locale& icu_locale, | |
47 Handle<Object> options) { | |
48 // Create time zone as specified by the user. We have to re-create time zone | |
49 // since calendar takes ownership. | |
50 icu::TimeZone* tz = NULL; | |
51 MaybeObject* maybe_object = options->GetProperty( | |
52 *isolate->factory()->NewStringFromAscii(CStrVector("timeZone"))); | |
53 Object* timezone; | |
54 if (maybe_object->ToObject(&timezone) && timezone->IsString()) { | |
55 v8::String::Utf8Value utf8_timezone( | |
56 v8::Utils::ToLocal(Handle<String>(String::cast(timezone)))); | |
57 icu::UnicodeString u_timezone(icu::UnicodeString::fromUTF8(*utf8_timezone)); | |
58 tz = icu::TimeZone::createTimeZone(u_timezone); | |
59 } else { | |
60 tz = icu::TimeZone::createDefault(); | |
61 } | |
62 | |
63 // Create a calendar using locale, and apply time zone to it. | |
64 UErrorCode status = U_ZERO_ERROR; | |
65 icu::Calendar* calendar = | |
66 icu::Calendar::createInstance(tz, icu_locale, status); | |
67 | |
68 // Make formatter from skeleton. Calendar and numbering system are added | |
69 // to the locale as Unicode extension (if they were specified at all). | |
70 icu::SimpleDateFormat* date_format = NULL; | |
71 Object* skeleton; | |
72 maybe_object = options->GetProperty( | |
73 *isolate->factory()->NewStringFromAscii(CStrVector("skeleton"))); | |
74 if (maybe_object->ToObject(&skeleton) && skeleton->IsString()) { | |
75 v8::String::Utf8Value utf8_skeleton( | |
76 v8::Utils::ToLocal(Handle<String>(String::cast(skeleton)))); | |
77 icu::UnicodeString u_skeleton(icu::UnicodeString::fromUTF8(*utf8_skeleton)); | |
78 icu::DateTimePatternGenerator* generator = | |
79 icu::DateTimePatternGenerator::createInstance(icu_locale, status); | |
80 icu::UnicodeString pattern; | |
81 if (U_SUCCESS(status)) { | |
82 pattern = generator->getBestPattern(u_skeleton, status); | |
83 delete generator; | |
84 } | |
85 | |
86 date_format = new icu::SimpleDateFormat(pattern, icu_locale, status); | |
87 if (U_SUCCESS(status)) { | |
88 date_format->adoptCalendar(calendar); | |
89 } | |
90 } | |
91 | |
92 if (U_FAILURE(status)) { | |
93 delete calendar; | |
94 delete date_format; | |
95 date_format = NULL; | |
96 } | |
97 | |
98 return date_format; | |
99 } | |
100 | |
101 | |
102 void SetResolvedSettings(Isolate* isolate, | |
103 const icu::Locale& icu_locale, | |
104 icu::SimpleDateFormat* date_format, | |
105 Handle<JSObject> resolved) { | |
106 UErrorCode status = U_ZERO_ERROR; | |
107 icu::UnicodeString pattern; | |
108 date_format->toPattern(pattern); | |
109 JSObject::SetProperty( | |
110 resolved, | |
111 isolate->factory()->NewStringFromAscii(CStrVector("pattern")), | |
112 isolate->factory()->NewStringFromTwoByte( | |
113 Vector<const uint16_t>( | |
114 reinterpret_cast<const uint16_t*>(pattern.getBuffer()), | |
115 pattern.length())), | |
116 NONE, | |
117 kNonStrictMode); | |
118 | |
119 // Set time zone and calendar. | |
120 const icu::Calendar* calendar = date_format->getCalendar(); | |
121 const char* calendar_name = calendar->getType(); | |
122 JSObject::SetProperty( | |
123 resolved, | |
124 isolate->factory()->NewStringFromAscii(CStrVector("calendar")), | |
125 isolate->factory()->NewStringFromAscii(CStrVector(calendar_name)), | |
126 NONE, | |
127 kNonStrictMode); | |
128 | |
129 const icu::TimeZone& tz = calendar->getTimeZone(); | |
130 icu::UnicodeString time_zone; | |
131 tz.getID(time_zone); | |
132 | |
133 icu::UnicodeString canonical_time_zone; | |
134 icu::TimeZone::getCanonicalID(time_zone, canonical_time_zone, status); | |
135 if (U_SUCCESS(status)) { | |
136 if (canonical_time_zone == UNICODE_STRING_SIMPLE("Etc/GMT")) { | |
137 JSObject::SetProperty( | |
138 resolved, | |
139 isolate->factory()->NewStringFromAscii(CStrVector("timeZone")), | |
140 isolate->factory()->NewStringFromAscii(CStrVector("UTC")), | |
141 NONE, | |
142 kNonStrictMode); | |
143 } else { | |
144 JSObject::SetProperty( | |
145 resolved, | |
146 isolate->factory()->NewStringFromAscii(CStrVector("timeZone")), | |
147 isolate->factory()->NewStringFromTwoByte( | |
148 Vector<const uint16_t>( | |
149 reinterpret_cast<const uint16_t*>( | |
150 canonical_time_zone.getBuffer()), | |
151 canonical_time_zone.length())), | |
152 NONE, | |
153 kNonStrictMode); | |
154 } | |
155 } | |
156 | |
157 // Ugly hack. ICU doesn't expose numbering system in any way, so we have | |
158 // to assume that for given locale NumberingSystem constructor produces the | |
159 // same digits as NumberFormat/Calendar would. | |
160 status = U_ZERO_ERROR; | |
161 icu::NumberingSystem* numbering_system = | |
162 icu::NumberingSystem::createInstance(icu_locale, status); | |
163 if (U_SUCCESS(status)) { | |
164 const char* ns = numbering_system->getName(); | |
165 JSObject::SetProperty( | |
166 resolved, | |
167 isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")), | |
168 isolate->factory()->NewStringFromAscii(CStrVector(ns)), | |
169 NONE, | |
170 kNonStrictMode); | |
171 } else { | |
172 JSObject::SetProperty( | |
173 resolved, | |
174 isolate->factory()->NewStringFromAscii(CStrVector("numberingSystem")), | |
175 isolate->factory()->undefined_value(), | |
176 NONE, | |
177 kNonStrictMode); | |
178 } | |
179 delete numbering_system; | |
180 | |
181 // Set the locale | |
182 char result[ULOC_FULLNAME_CAPACITY]; | |
183 status = U_ZERO_ERROR; | |
184 uloc_toLanguageTag( | |
185 icu_locale.getName(), result, ULOC_FULLNAME_CAPACITY, FALSE, &status); | |
186 if (U_SUCCESS(status)) { | |
187 JSObject::SetProperty( | |
188 resolved, | |
189 isolate->factory()->NewStringFromAscii(CStrVector("locale")), | |
190 isolate->factory()->NewStringFromAscii(CStrVector(result)), | |
191 NONE, | |
192 kNonStrictMode); | |
193 } else { | |
194 // This would never happen, since we got the locale from ICU. | |
195 JSObject::SetProperty( | |
196 resolved, | |
197 isolate->factory()->NewStringFromAscii(CStrVector("locale")), | |
198 isolate->factory()->NewStringFromAscii(CStrVector("und")), | |
199 NONE, | |
200 kNonStrictMode); | |
201 } | |
202 } | |
203 | |
204 | |
205 template<int internal_fields, EternalHandles::SingletonHandle field> | |
206 Handle<ObjectTemplateInfo> GetEternal(Isolate* isolate) { | |
207 if (isolate->eternal_handles()->Exists(field)) { | |
208 return Handle<ObjectTemplateInfo>::cast( | |
209 isolate->eternal_handles()->GetSingleton(field)); | |
210 } | |
211 v8::Local<v8::ObjectTemplate> raw_template(v8::ObjectTemplate::New()); | |
212 raw_template->SetInternalFieldCount(internal_fields); | |
213 return Handle<ObjectTemplateInfo>::cast( | |
214 isolate->eternal_handles()->CreateSingleton( | |
215 isolate, | |
216 *v8::Utils::OpenHandle(*raw_template), | |
217 field)); | |
218 } | |
219 | |
220 } // namespace | |
221 | |
222 | |
223 // static | |
224 Handle<ObjectTemplateInfo> I18N::GetTemplate(Isolate* isolate) { | |
225 return GetEternal<1, i::EternalHandles::I18N_TEMPLATE_ONE>(isolate); | |
226 } | |
227 | |
228 | |
229 // static | |
230 Handle<ObjectTemplateInfo> I18N::GetTemplate2(Isolate* isolate) { | |
231 return GetEternal<2, i::EternalHandles::I18N_TEMPLATE_TWO>(isolate); | |
232 } | |
233 | |
234 | |
235 // static | |
236 icu::SimpleDateFormat* DateFormat::InitializeDateTimeFormat( | |
237 Isolate* isolate, | |
238 Handle<String> locale, | |
239 Handle<JSObject> options, | |
240 Handle<JSObject> resolved) { | |
241 // Convert BCP47 into ICU locale format. | |
242 UErrorCode status = U_ZERO_ERROR; | |
243 icu::Locale icu_locale; | |
244 char icu_result[ULOC_FULLNAME_CAPACITY]; | |
245 int icu_length = 0; | |
246 v8::String::Utf8Value bcp47_locale(v8::Utils::ToLocal(locale)); | |
247 if (bcp47_locale.length() != 0) { | |
248 uloc_forLanguageTag(*bcp47_locale, icu_result, ULOC_FULLNAME_CAPACITY, | |
249 &icu_length, &status); | |
250 if (U_FAILURE(status) || icu_length == 0) { | |
251 return NULL; | |
252 } | |
253 icu_locale = icu::Locale(icu_result); | |
254 } | |
255 | |
256 icu::SimpleDateFormat* date_format = CreateICUDateFormat( | |
257 isolate, icu_locale, options); | |
258 if (!date_format) { | |
259 // Remove extensions and try again. | |
260 icu::Locale no_extension_locale(icu_locale.getBaseName()); | |
261 date_format = CreateICUDateFormat(isolate, no_extension_locale, options); | |
262 | |
263 // Set resolved settings (pattern, numbering system, calendar). | |
264 SetResolvedSettings(isolate, no_extension_locale, date_format, resolved); | |
265 } else { | |
266 SetResolvedSettings(isolate, icu_locale, date_format, resolved); | |
267 } | |
268 | |
269 return date_format; | |
270 } | |
271 | |
272 | |
273 icu::SimpleDateFormat* DateFormat::UnpackDateFormat( | |
274 Isolate* isolate, | |
275 Handle<JSObject> obj) { | |
276 if (obj->HasLocalProperty( | |
277 *isolate->factory()->NewStringFromAscii(CStrVector("dateFormat")))) { | |
278 return reinterpret_cast<icu::SimpleDateFormat*>( | |
279 obj->GetInternalField(0)); | |
280 } | |
281 | |
282 return NULL; | |
283 } | |
284 | |
285 | |
286 void DateFormat::DeleteDateFormat(v8::Isolate* isolate, | |
287 Persistent<v8::Object>* object, | |
288 void* param) { | |
289 // First delete the hidden C++ object. | |
290 delete reinterpret_cast<icu::SimpleDateFormat*>(Handle<JSObject>::cast( | |
291 v8::Utils::OpenPersistent(object))->GetInternalField(0)); | |
292 | |
293 // Then dispose of the persistent handle to JS object. | |
294 object->Dispose(isolate); | |
295 } | |
296 | |
297 } } // namespace v8::internal | |
OLD | NEW |