Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Side by Side Diff: src/extensions/experimental/datetime-format.cc

Issue 7014019: Adding DateTimeFormat class to i18n API. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: ascii->utf8. Added narrow and standalone. Added short, medium, long and full to types. Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
1 // Copyright 2011 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
28 #include "datetime-format.h"
29
30 #include "i18n-utils.h"
31 #include "unicode/dtfmtsym.h"
32 #include "unicode/dtptngen.h"
33 #include "unicode/locid.h"
34 #include "unicode/smpdtfmt.h"
35
36 namespace v8 {
37 namespace internal {
38
39 v8::Persistent<v8::FunctionTemplate> DateTimeFormat::datetime_format_template_;
40
41 static icu::DateFormat* CreateDateTimeFormat(v8::Handle<v8::String>,
42 v8::Handle<v8::Object>);
43 static v8::Handle<v8::Value> GetSymbols(
44 const v8::Arguments&,
45 const icu::UnicodeString*, int32_t,
46 const icu::UnicodeString*, int32_t,
47 const icu::UnicodeString*, int32_t);
48 static v8::Handle<v8::Value> ThrowUnexpectedObjectError();
49 static icu::DateFormat::EStyle GetDateTimeStyle(const icu::UnicodeString&);
50
51 icu::SimpleDateFormat* DateTimeFormat::UnpackDateTimeFormat(
52 v8::Handle<v8::Object> obj) {
53 if (datetime_format_template_->HasInstance(obj)) {
54 return static_cast<icu::SimpleDateFormat*>(
55 obj->GetPointerFromInternalField(0));
56 }
57
58 return NULL;
59 }
60
61 void DateTimeFormat::DeleteDateTimeFormat(v8::Persistent<v8::Value> object,
62 void* param) {
63 v8::Persistent<v8::Object> persistent_object =
64 v8::Persistent<v8::Object>::Cast(object);
65
66 // First delete the hidden C++ object.
67 // Unpacking should never return NULL here. That would only happen if
68 // this method is used as the weak callback for persistent handles not
69 // pointing to a date time formatter.
70 delete UnpackDateTimeFormat(persistent_object);
71
72 // Then dispose of the persistent handle to JS object.
73 persistent_object.Dispose();
74 }
75
76 v8::Handle<v8::Value> DateTimeFormat::Format(const v8::Arguments& args) {
77 v8::HandleScope handle_scope;
78
79 double millis = 0.0;
80 if (args.Length() != 1 || !args[0]->IsDate()) {
81 // Create a new date.
82 v8::TryCatch try_catch;
83 v8::Local<v8::Script> date_script =
84 v8::Script::Compile(v8::String::New("eval('new Date()')"));
85 millis = date_script->Run()->NumberValue();
86 if (try_catch.HasCaught()) {
87 return try_catch.ReThrow();
88 }
89 } else {
90 millis = v8::Date::Cast(*args[0])->NumberValue();
91 }
92
93 icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
94 if (!date_format) {
95 return ThrowUnexpectedObjectError();
96 }
97
98 icu::UnicodeString result;
99 date_format->format(millis, result);
100
101 return v8::String::New(
102 reinterpret_cast<const uint16_t*>(result.getBuffer()), result.length());
103 }
104
105 v8::Handle<v8::Value> DateTimeFormat::GetMonths(const v8::Arguments& args) {
106 icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
107 if (!date_format) {
108 return ThrowUnexpectedObjectError();
109 }
110
111 const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
112
113 int32_t narrow_count;
114 const icu::UnicodeString* narrow = symbols->getMonths(
115 narrow_count,
116 icu::DateFormatSymbols::STANDALONE,
117 icu::DateFormatSymbols::NARROW);
118 int32_t abbrev_count;
119 const icu::UnicodeString* abbrev = symbols->getMonths(
120 abbrev_count,
121 icu::DateFormatSymbols::STANDALONE,
122 icu::DateFormatSymbols::ABBREVIATED);
123 int32_t wide_count;
124 const icu::UnicodeString* wide = symbols->getMonths(
125 wide_count,
126 icu::DateFormatSymbols::STANDALONE,
127 icu::DateFormatSymbols::WIDE);
128
129 return GetSymbols(
130 args, narrow, narrow_count, abbrev, abbrev_count, wide, wide_count);
131 }
132
133 v8::Handle<v8::Value> DateTimeFormat::GetWeekdays(const v8::Arguments& args) {
134 icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
135 if (!date_format) {
136 ThrowUnexpectedObjectError();
137 }
138
139 const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
140
141 int32_t narrow_count;
142 const icu::UnicodeString* narrow = symbols->getWeekdays(
143 narrow_count,
144 icu::DateFormatSymbols::STANDALONE,
145 icu::DateFormatSymbols::NARROW);
146 int32_t abbrev_count;
147 const icu::UnicodeString* abbrev = symbols->getWeekdays(
148 abbrev_count,
149 icu::DateFormatSymbols::STANDALONE,
150 icu::DateFormatSymbols::ABBREVIATED);
151 int32_t wide_count;
152 const icu::UnicodeString* wide = symbols->getWeekdays(
153 wide_count,
154 icu::DateFormatSymbols::STANDALONE,
155 icu::DateFormatSymbols::WIDE);
156
157 // getXXXWeekdays always returns 8 elements.
158 ASSERT_EQ(8, narrow_count);
159 ASSERT_EQ(8, abbrev_count);
160 ASSERT_EQ(8, wide_count);
161
162 // ICU documentation says we should ignore element 0 of the returned array.
163 return GetSymbols(args, narrow + 1, narrow_count - 1, abbrev + 1,
164 abbrev_count -1 , wide + 1, wide_count - 1);
165 }
166
167 v8::Handle<v8::Value> DateTimeFormat::GetEras(const v8::Arguments& args) {
168 icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
169 if (!date_format) {
170 return ThrowUnexpectedObjectError();
171 }
172
173 const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
174
175 int32_t narrow_count;
176 const icu::UnicodeString* narrow = symbols->getNarrowEras(narrow_count);
177 int32_t abbrev_count;
178 const icu::UnicodeString* abbrev = symbols->getEras(abbrev_count);
179 int32_t wide_count;
180 const icu::UnicodeString* wide = symbols->getEraNames(wide_count);
181
182 return GetSymbols(
183 args, narrow, narrow_count, abbrev, abbrev_count, wide, wide_count);
184 }
185
186 v8::Handle<v8::Value> DateTimeFormat::GetAmPm(const v8::Arguments& args) {
187 icu::SimpleDateFormat* date_format = UnpackDateTimeFormat(args.Holder());
188 if (!date_format) {
189 return ThrowUnexpectedObjectError();
190 }
191
192 const icu::DateFormatSymbols* symbols = date_format->getDateFormatSymbols();
193
194 // In this case narrow == abbreviated == wide
195 int32_t count;
196 const icu::UnicodeString* wide = symbols->getAmPmStrings(count);
197
198 return GetSymbols(args, wide, count, wide, count, wide, count);
199 }
200
201 v8::Handle<v8::Value> DateTimeFormat::JSDateTimeFormat(
202 const v8::Arguments& args) {
203 v8::HandleScope handle_scope;
204
205 ASSERT_EQ(2, args.Length());
206 // LanguageID string.
207 ASSERT(args[0]->IsString());
208 // Settings object.
209 ASSERT(args[1]->IsObject());
210
211 icu::SimpleDateFormat* date_format = static_cast<icu::SimpleDateFormat*>(
212 CreateDateTimeFormat(args[0]->ToString(), args[1]->ToObject()));
213
214 if (datetime_format_template_.IsEmpty()) {
215 v8::Local<v8::FunctionTemplate> raw_template(v8::FunctionTemplate::New());
216
217 raw_template->SetClassName(v8::String::New("v8Locale.DateTimeFormat"));
218
219 // Define internal field count on instance template.
220 v8::Local<v8::ObjectTemplate> object_template =
221 raw_template->InstanceTemplate();
222
223 // Set aside internal field for icu date time formatter.
224 object_template->SetInternalFieldCount(1);
225
226 // Define all of the prototype methods on prototype template.
227 v8::Local<v8::ObjectTemplate> proto = raw_template->PrototypeTemplate();
228 proto->Set(v8::String::New("format"),
229 v8::FunctionTemplate::New(Format));
230 proto->Set(v8::String::New("getMonths"),
231 v8::FunctionTemplate::New(GetMonths));
232 proto->Set(v8::String::New("getWeekdays"),
233 v8::FunctionTemplate::New(GetWeekdays));
234 proto->Set(v8::String::New("getEras"),
235 v8::FunctionTemplate::New(GetEras));
236 proto->Set(v8::String::New("getAmPm"),
237 v8::FunctionTemplate::New(GetAmPm));
238
239 datetime_format_template_ =
240 v8::Persistent<v8::FunctionTemplate>::New(raw_template);
241 }
242
243 // Create an empty object wrapper.
244 v8::Local<v8::Object> local_object =
245 datetime_format_template_->GetFunction()->NewInstance();
246 v8::Persistent<v8::Object> wrapper =
247 v8::Persistent<v8::Object>::New(local_object);
248
249 // Set date time formatter as internal field of the resulting JS object.
250 wrapper->SetPointerInInternalField(0, date_format);
251
252 // Set resolved pattern in options.pattern.
253 icu::UnicodeString pattern;
254 date_format->toPattern(pattern);
255 v8::Local<v8::Object> options = v8::Object::New();
256 options->Set(v8::String::New("pattern"),
257 v8::String::New(reinterpret_cast<const uint16_t*>(
258 pattern.getBuffer()), pattern.length()));
259 wrapper->Set(v8::String::New("options"), options);
260
261 // Make object handle weak so we can delete iterator once GC kicks in.
262 wrapper.MakeWeak(NULL, DeleteDateTimeFormat);
263
264 return wrapper;
265 }
266
267 // Returns SimpleDateFormat.
268 static icu::DateFormat* CreateDateTimeFormat(
269 v8::Handle<v8::String> locale, v8::Handle<v8::Object> settings) {
270 v8::HandleScope handle_scope;
271
272 v8::String::AsciiValue ascii_locale(locale);
273 icu::Locale icu_locale(*ascii_locale);
274
275 // Make formatter from skeleton.
276 icu::SimpleDateFormat* date_format = NULL;
277 UErrorCode status = U_ZERO_ERROR;
278 icu::UnicodeString skeleton;
279 if (I18NUtils::ExtractStringSetting(settings, "skeleton", &skeleton)) {
280 v8::Local<icu::DateTimePatternGenerator> generator(
281 icu::DateTimePatternGenerator::createInstance(icu_locale, status));
282 icu::UnicodeString pattern =
283 generator->getBestPattern(skeleton, status);
284
285 date_format = new icu::SimpleDateFormat(pattern, icu_locale, status);
286 if (U_SUCCESS(status)) {
287 return date_format;
288 } else {
289 delete date_format;
290 }
291 }
292
293 // Extract date type and time type from settings.
294 icu::UnicodeString date_type;
295 icu::DateFormat::EStyle date_style = icu::DateFormat::kNone;
296 if (I18NUtils::ExtractStringSetting(settings, "dateType", &date_type)) {
297 date_style = GetDateTimeStyle(date_type);
298 }
299
300 icu::UnicodeString time_type;
301 icu::DateFormat::EStyle time_style = icu::DateFormat::kNone;
302 if (I18NUtils::ExtractStringSetting(settings, "timeType", &time_type)) {
303 time_style = GetDateTimeStyle(time_type);
304 }
305
306 // Try all combinations of date/time types.
307 if (date_style == icu::DateFormat::kNone &&
308 time_style == icu::DateFormat::kNone) {
309 // Return default short date, short
310 return icu::DateFormat::createDateTimeInstance(
311 icu::DateFormat::kShort, icu::DateFormat::kShort, icu_locale);
312 } else if (date_style != icu::DateFormat::kNone &&
313 time_style != icu::DateFormat::kNone) {
314 return icu::DateFormat::createDateTimeInstance(
315 date_style, time_style, icu_locale);
316 } else if (date_style != icu::DateFormat::kNone) {
317 return icu::DateFormat::createDateInstance(date_style, icu_locale);
318 } else {
319 // time_style != icu::DateFormat::kNone
320 return icu::DateFormat::createTimeInstance(time_style, icu_locale);
321 }
322 }
323
324 // Creates a v8::Array of narrow, abbrev or wide symbols.
325 static v8::Handle<v8::Value> GetSymbols(const v8::Arguments& args,
326 const icu::UnicodeString* narrow,
327 int32_t narrow_count,
328 const icu::UnicodeString* abbrev,
329 int32_t abbrev_count,
330 const icu::UnicodeString* wide,
331 int32_t wide_count) {
332 v8::HandleScope handle_scope;
333
334 // Make wide width default.
335 const icu::UnicodeString* result = wide;
336 int32_t count = wide_count;
337
338 if (args.Length() == 1 && args[0]->IsString()) {
339 v8::String::AsciiValue ascii_value(args[0]);
340 if (strcmp(*ascii_value, "abbreviated") == 0) {
341 result = abbrev;
342 count = abbrev_count;
343 } else if (strcmp(*ascii_value, "narrow") == 0) {
344 result = narrow;
345 count = narrow_count;
346 }
347 }
348
349 v8::Handle<v8::Array> symbols = v8::Array::New();
350 for (int32_t i = 0; i < count; ++i) {
351 symbols->Set(i, v8::String::New(
352 reinterpret_cast<const uint16_t*>(result[i].getBuffer()),
353 result[i].length()));
354 }
355
356 return handle_scope.Close(symbols);
357 }
358
359 // Throws a JavaScript exception.
360 static v8::Handle<v8::Value> ThrowUnexpectedObjectError() {
361 // Returns undefined, and schedules an exception to be thrown.
362 return v8::ThrowException(v8::Exception::Error(
363 v8::String::New("DateTimeFormat method called on an object "
364 "that is not a DateTimeFormat.")));
365 }
366
367 // Returns icu date/time style.
368 static icu::DateFormat::EStyle GetDateTimeStyle(
369 const icu::UnicodeString& type) {
370 if (type == UNICODE_STRING_SIMPLE("medium")) {
371 return icu::DateFormat::kMedium;
372 } else if (type == UNICODE_STRING_SIMPLE("long")) {
373 return icu::DateFormat::kLong;
374 } else if (type == UNICODE_STRING_SIMPLE("full")) {
375 return icu::DateFormat::kFull;
376 }
377
378 return icu::DateFormat::kShort;
379 }
380
381 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/extensions/experimental/datetime-format.h ('k') | src/extensions/experimental/experimental.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698