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

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

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