~ubuntu-branches/ubuntu/saucy/libv8/saucy

« back to all changes in this revision

Viewing changes to src/extensions/experimental/datetime-format.cc

  • Committer: Package Import Robot
  • Author(s): Jérémy Lal
  • Date: 2012-04-07 16:26:13 UTC
  • mfrom: (15.1.27 sid)
  • Revision ID: package-import@ubuntu.com-20120407162613-dqo1m6w9r3fh8tst
Tags: 3.8.9.16-3
* mipsel build fixes :
  + v8_use_mips_abi_hardfloat=false, this lowers EABI requirements.
  + v8_can_use_fpu_instructions=false, detect if FPU is present.
  + set -Wno-unused-but-set-variable only on mipsel.

Show diffs side-by-side

added added

removed removed

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