Move LocaleWin.{cpp,h} to platform/text/win/
[WebKit-https.git] / Source / WebCore / platform / text / win / LocaleWin.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "LocaleWin.h"
33
34 #include "DateComponents.h"
35 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
36 #include "DateTimeFormat.h"
37 #endif
38 #include "Language.h"
39 #include "LocalizedStrings.h"
40 #include <limits>
41 #include <windows.h>
42 #include <wtf/CurrentTime.h>
43 #include <wtf/DateMath.h>
44 #include <wtf/OwnPtr.h>
45 #include <wtf/PassOwnPtr.h>
46 #include <wtf/text/StringBuilder.h>
47
48 using namespace std;
49
50 namespace WebCore {
51
52 typedef LCID (WINAPI* LocaleNameToLCIDPtr)(LPCWSTR, DWORD);
53
54 static String extractLanguageCode(const String& locale)
55 {
56     size_t dashPosition = locale.find('-');
57     if (dashPosition == notFound)
58         return locale;
59     return locale.left(dashPosition);
60 }
61
62 static LCID LCIDFromLocaleInternal(LCID userDefaultLCID, const String& userDefaultLanguageCode, LocaleNameToLCIDPtr localeNameToLCID, String& locale)
63 {
64     String localeLanguageCode = extractLanguageCode(locale);
65     if (equalIgnoringCase(localeLanguageCode, userDefaultLanguageCode))
66         return userDefaultLCID;
67     return localeNameToLCID(locale.charactersWithNullTermination(), 0);
68 }
69
70 static LCID LCIDFromLocale(const AtomicString& locale)
71 {
72     // LocaleNameToLCID() is available since Windows Vista.
73     LocaleNameToLCIDPtr localeNameToLCID = reinterpret_cast<LocaleNameToLCIDPtr>(::GetProcAddress(::GetModuleHandle(L"kernel32"), "LocaleNameToLCID"));
74     if (!localeNameToLCID)
75         return LOCALE_USER_DEFAULT;
76
77     // According to MSDN, 9 is enough for LOCALE_SISO639LANGNAME.
78     const size_t languageCodeBufferSize = 9;
79     WCHAR lowercaseLanguageCode[languageCodeBufferSize];
80     ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lowercaseLanguageCode, languageCodeBufferSize);
81     String userDefaultLanguageCode = String(lowercaseLanguageCode);
82
83     LCID lcid = LCIDFromLocaleInternal(LOCALE_USER_DEFAULT, userDefaultLanguageCode, localeNameToLCID, String(locale));
84     if (!lcid)
85         lcid = LCIDFromLocaleInternal(LOCALE_USER_DEFAULT, userDefaultLanguageCode, localeNameToLCID, defaultLanguage());
86     return lcid;
87 }
88
89 PassOwnPtr<Locale> Locale::create(const AtomicString& locale)
90 {
91     return LocaleWin::create(LCIDFromLocale(locale));
92 }
93
94 // Windows doesn't have an API to parse locale-specific date string,
95 // and GetDateFormat() and GetDateFormatEx() don't support years older
96 // than 1600, which we should support according to the HTML
97 // standard. So, we obtain the date format from the system, but we
98 // format/parse a date by our own code.
99
100 inline LocaleWin::LocaleWin(LCID lcid)
101     : m_lcid(lcid)
102     , m_didInitializeNumberData(false)
103 {
104     SYSTEMTIME systemTime;
105     GetLocalTime(&systemTime);
106     m_baseYear = systemTime.wYear;
107
108 #if ENABLE(CALENDAR_PICKER)
109     DWORD value = 0;
110     getLocaleInfo(LOCALE_IFIRSTDAYOFWEEK, value);
111     // 0:Monday, ..., 6:Sunday.
112     // We need 1 for Monday, 0 for Sunday.
113     m_firstDayOfWeek = (value + 1) % 7;
114 #endif
115 }
116
117 PassOwnPtr<LocaleWin> LocaleWin::create(LCID lcid)
118 {
119     return adoptPtr(new LocaleWin(lcid));
120 }
121
122 LocaleWin::~LocaleWin()
123 {
124 }
125
126 String LocaleWin::getLocaleInfoString(LCTYPE type)
127 {
128     int bufferSizeWithNUL = ::GetLocaleInfo(m_lcid, type, 0, 0);
129     if (bufferSizeWithNUL <= 0)
130         return String();
131     Vector<UChar> buffer(bufferSizeWithNUL);
132     ::GetLocaleInfo(m_lcid, type, buffer.data(), bufferSizeWithNUL);
133     buffer.shrink(bufferSizeWithNUL - 1);
134     return String::adopt(buffer);
135 }
136
137 void LocaleWin::getLocaleInfo(LCTYPE type, DWORD& result)
138 {
139     ::GetLocaleInfo(m_lcid, type | LOCALE_RETURN_NUMBER, reinterpret_cast<LPWSTR>(&result), sizeof(DWORD) / sizeof(TCHAR));
140 }
141
142 void LocaleWin::ensureShortMonthLabels()
143 {
144     if (!m_shortMonthLabels.isEmpty())
145         return;
146     const LCTYPE types[12] = {
147         LOCALE_SABBREVMONTHNAME1,
148         LOCALE_SABBREVMONTHNAME2,
149         LOCALE_SABBREVMONTHNAME3,
150         LOCALE_SABBREVMONTHNAME4,
151         LOCALE_SABBREVMONTHNAME5,
152         LOCALE_SABBREVMONTHNAME6,
153         LOCALE_SABBREVMONTHNAME7,
154         LOCALE_SABBREVMONTHNAME8,
155         LOCALE_SABBREVMONTHNAME9,
156         LOCALE_SABBREVMONTHNAME10,
157         LOCALE_SABBREVMONTHNAME11,
158         LOCALE_SABBREVMONTHNAME12,
159     };
160     m_shortMonthLabels.reserveCapacity(WTF_ARRAY_LENGTH(types));
161     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(types); ++i) {
162         m_shortMonthLabels.append(getLocaleInfoString(types[i]));
163         if (m_shortMonthLabels.last().isEmpty()) {
164             m_shortMonthLabels.shrink(0);
165             m_shortMonthLabels.reserveCapacity(WTF_ARRAY_LENGTH(WTF::monthName));
166             for (unsigned m = 0; m < WTF_ARRAY_LENGTH(WTF::monthName); ++m)
167                 m_shortMonthLabels.append(WTF::monthName[m]);
168             return;
169         }
170     }
171 }
172
173 // -------------------------------- Tokenized date format
174
175 struct DateFormatToken {
176     enum Type {
177         Literal,
178         Day1,
179         Day2,
180         Month1,
181         Month2,
182         Month3,
183         Month4,
184         Year1,
185         Year2,
186         Year4,
187     };
188     Type type;
189     String data; // This is valid only if type==Literal.
190
191     DateFormatToken(Type type)
192         : type(type)
193     { }
194
195     DateFormatToken(const String& data)
196         : type(Literal)
197         , data(data)
198     { }
199
200     DateFormatToken(const DateFormatToken& token)
201         : type(token.type)
202         , data(token.data)
203     { }
204 };
205
206 static inline bool isEraSymbol(UChar letter) { return letter == 'g'; }
207 static inline bool isYearSymbol(UChar letter) { return letter == 'y'; }
208 static inline bool isMonthSymbol(UChar letter) { return letter == 'M'; }
209 static inline bool isDaySymbol(UChar letter) { return letter == 'd'; }
210
211 static unsigned countContinuousLetters(const String& format, unsigned index)
212 {
213     unsigned count = 1;
214     UChar reference = format[index];
215     while (index + 1 < format.length()) {
216         if (format[++index] != reference)
217             break;
218         ++count;
219     }
220     return count;
221 }
222
223 static void commitLiteralToken(StringBuilder& literalBuffer, Vector<DateFormatToken>& tokens)
224 {
225     if (literalBuffer.length() <= 0)
226         return;
227     tokens.append(DateFormatToken(literalBuffer.toString()));
228     literalBuffer.clear();
229 }
230
231 // See http://msdn.microsoft.com/en-us/library/dd317787(v=vs.85).aspx
232 static Vector<DateFormatToken> parseDateFormat(const String format)
233 {
234     Vector<DateFormatToken> tokens;
235     StringBuilder literalBuffer;
236     bool inQuote = false;
237     bool lastQuoteCanBeLiteral = false;
238     for (unsigned i = 0; i < format.length(); ++i) {
239         UChar ch = format[i];
240         if (inQuote) {
241             if (ch == '\'') {
242                 inQuote = false;
243                 ASSERT(i);
244                 if (lastQuoteCanBeLiteral && format[i - 1] == '\'') {
245                     literalBuffer.append('\'');
246                     lastQuoteCanBeLiteral = false;
247                 } else
248                     lastQuoteCanBeLiteral = true;
249             } else
250                 literalBuffer.append(ch);
251             continue;
252         }
253
254         if (ch == '\'') {
255             inQuote = true;
256             if (lastQuoteCanBeLiteral && i > 0 && format[i - 1] == '\'') {
257                 literalBuffer.append(ch);
258                 lastQuoteCanBeLiteral = false;
259             } else
260                 lastQuoteCanBeLiteral = true;
261         } else if (isYearSymbol(ch)) {
262             commitLiteralToken(literalBuffer, tokens);
263             unsigned count = countContinuousLetters(format, i);
264             i += count - 1;
265             if (count == 1)
266                 tokens.append(DateFormatToken(DateFormatToken::Year1));
267             else if (count == 2)
268                 tokens.append(DateFormatToken(DateFormatToken::Year2));
269             else
270                 tokens.append(DateFormatToken(DateFormatToken::Year4));
271         } else if (isMonthSymbol(ch)) {
272             commitLiteralToken(literalBuffer, tokens);
273             unsigned count = countContinuousLetters(format, i);
274             i += count - 1;
275             if (count == 1)
276                 tokens.append(DateFormatToken(DateFormatToken::Month1));
277             else if (count == 2)
278                 tokens.append(DateFormatToken(DateFormatToken::Month2));
279             else if (count == 3)
280                 tokens.append(DateFormatToken(DateFormatToken::Month3));
281             else
282                 tokens.append(DateFormatToken(DateFormatToken::Month4));
283         } else if (isDaySymbol(ch)) {
284             commitLiteralToken(literalBuffer, tokens);
285             unsigned count = countContinuousLetters(format, i);
286             i += count - 1;
287             if (count == 1)
288                 tokens.append(DateFormatToken(DateFormatToken::Day1));
289             else
290                 tokens.append(DateFormatToken(DateFormatToken::Day2));
291         } else if (isEraSymbol(ch)) {
292             // Just ignore era.
293             // HTML5 date supports only A.D.
294         } else
295             literalBuffer.append(ch);
296     }
297     commitLiteralToken(literalBuffer, tokens);
298     return tokens;
299 }
300
301 // -------------------------------- Parsing
302
303 bool LocaleWin::isLocalizedDigit(UChar ch)
304 {
305     String normalizedDigit = convertFromLocalizedNumber(String(&ch, 1));
306     if (normalizedDigit.length() != 1)
307         return false;
308     return isASCIIDigit(normalizedDigit[0]);
309 }
310
311 // Returns -1 if parsing fails.
312 int LocaleWin::parseNumber(const String& input, unsigned& index)
313 {
314     unsigned digitsStart = index;
315     while (index < input.length() && isASCIIDigit(input[index]))
316         index++;
317     if (digitsStart != index) {
318         bool ok = false;
319         int number = input.substring(digitsStart, index - digitsStart).toInt(&ok);
320         return ok ? number : -1;
321     }
322
323     while (index < input.length() && isLocalizedDigit(input[index]))
324         index++;
325     if (digitsStart == index)
326         return -1;
327     bool ok = false;
328     int number = convertFromLocalizedNumber(input.substring(digitsStart, index - digitsStart)).toInt(&ok);
329     return ok ? number : -1;
330 }
331
332 // Returns 0-based month number. Returns -1 if parsing fails.
333 int LocaleWin::parseNumberOrMonth(const String& input, unsigned& index)
334 {
335     int result = parseNumber(input, index);
336     if (result >= 0) {
337         if (result < 1 || result > 12)
338             return -1;
339         return result - 1;
340     }
341     for (unsigned m = 0; m < m_monthLabels.size(); ++m) {
342         unsigned labelLength = m_monthLabels[m].length();
343         if (equalIgnoringCase(input.substring(index, labelLength), m_monthLabels[m])) {
344             index += labelLength;
345             return m;
346         }
347     }
348     for (unsigned m = 0; m < m_shortMonthLabels.size(); ++m) {
349         unsigned labelLength = m_shortMonthLabels[m].length();
350         if (equalIgnoringCase(input.substring(index, labelLength), m_shortMonthLabels[m])) {
351             index += labelLength;
352             return m;
353         }
354     }
355     return -1;
356 }
357
358 double LocaleWin::parseDateTime(const String& input, DateComponents::Type type)
359 {
360     if (type != DateComponents::Date)
361         return std::numeric_limits<double>::quiet_NaN();
362     ensureShortDateTokens();
363     return parseDate(m_shortDateTokens, m_baseYear, input);
364 }
365
366 double LocaleWin::parseDate(const String& format, int baseYear, const String& input)
367 {
368     return parseDate(parseDateFormat(format), baseYear, input);
369 }
370
371 double LocaleWin::parseDate(const Vector<DateFormatToken>& tokens, int baseYear, const String& input)
372 {
373     ensureShortMonthLabels();
374     ensureMonthLabels();
375     const double NaN = numeric_limits<double>::quiet_NaN();
376     unsigned inputIndex = 0;
377     int day = -1, month = -1, year = -1;
378     for (unsigned i = 0; i < tokens.size(); ++i) {
379         switch (tokens[i].type) {
380         case DateFormatToken::Literal: {
381             String data = tokens[i].data;
382             unsigned literalLength = data.length();
383             if (input.substring(inputIndex, literalLength) == data)
384                 inputIndex += literalLength;
385             // Go ahead even if the input doesn't have this string.
386             break;
387         }
388         case DateFormatToken::Day1:
389         case DateFormatToken::Day2:
390             day = parseNumber(input, inputIndex);
391             if (day < 1 || day > 31)
392                 return NaN;
393             break;
394         case DateFormatToken::Month1:
395         case DateFormatToken::Month2:
396         case DateFormatToken::Month3:
397         case DateFormatToken::Month4:
398             month = parseNumberOrMonth(input, inputIndex);
399             if (month < 0 || month > 11)
400                 return NaN;
401             break;
402         case DateFormatToken::Year1: {
403             unsigned oldIndex = inputIndex;
404             year = parseNumber(input, inputIndex);
405             if (year <= 0)
406                 return NaN;
407             if (inputIndex - oldIndex == 1) {
408                 int shortYear = baseYear % 10;
409                 int decade = baseYear - shortYear;
410                 if (shortYear >= 5)
411                     year += shortYear - 4 <= year ? decade : decade + 10;
412                 else
413                     year += shortYear + 5 >= year ? decade : decade - 10;
414             }
415             break;
416         }
417         case DateFormatToken::Year2: {
418             unsigned oldIndex = inputIndex;
419             year = parseNumber(input, inputIndex);
420             if (year <= 0)
421                 return NaN;
422             if (inputIndex - oldIndex == 2) {
423                 int shortYear = baseYear % 100;
424                 int century = baseYear - shortYear;
425                 if (shortYear >= 50)
426                     year += shortYear - 49 <= year ? century : century + 100;
427                 else
428                     year += shortYear + 50 >= year ? century : century - 100;
429             }
430             break;
431         }
432         case DateFormatToken::Year4:
433             year = parseNumber(input, inputIndex);
434             if (year <= 0)
435                 return NaN;
436             break;
437         }
438     }
439     if (year <= 0 || month < 0 || day <= 0)
440         return NaN;
441     return dateToDaysFrom1970(year, month, day) * msPerDay;
442 }
443
444 // -------------------------------- Formatting
445
446 void LocaleWin::ensureShortDateTokens()
447 {
448     if (!m_shortDateTokens.isEmpty())
449         return;
450     m_shortDateTokens = parseDateFormat(getLocaleInfoString(LOCALE_SSHORTDATE));
451 }
452
453 static String substituteLabelsIntoFormat(const Vector<DateFormatToken>& tokens, const String& yearText, const String& monthText, const String& dayText)
454 {
455     String nonEmptyDayText = dayText.isEmpty() ? "Day" : dayText;
456     String nonEmptyMonthText = monthText.isEmpty() ? "Month" : monthText;
457     String nonEmptyYearText = yearText.isEmpty() ? "Year" : yearText;
458     StringBuilder buffer;
459     for (unsigned i = 0; i < tokens.size(); ++i) {
460         switch (tokens[i].type) {
461         case DateFormatToken::Literal:
462             buffer.append(tokens[i].data);
463             break;
464         case DateFormatToken::Day1:
465         case DateFormatToken::Day2:
466             buffer.append(nonEmptyDayText);
467             break;
468         case DateFormatToken::Month1:
469         case DateFormatToken::Month2:
470         case DateFormatToken::Month3:
471         case DateFormatToken::Month4:
472             buffer.append(nonEmptyMonthText);
473             break;
474         case DateFormatToken::Year1:
475         case DateFormatToken::Year2:
476         case DateFormatToken::Year4:
477             buffer.append(nonEmptyYearText);
478             break;
479         }
480     }
481     return buffer.toString();
482 }
483
484 String LocaleWin::dateFormatText()
485 {
486     ensureShortDateTokens();
487     return substituteLabelsIntoFormat(m_shortDateTokens, dateFormatYearText(), dateFormatMonthText(), dateFormatDayInMonthText());
488 }
489
490 String LocaleWin::dateFormatText(const String& format, const String& yearText, const String& monthText, const String& dayText)
491 {
492     return substituteLabelsIntoFormat(parseDateFormat(format), yearText, monthText, dayText);
493 }
494
495 void LocaleWin::ensureMonthLabels()
496 {
497     if (!m_monthLabels.isEmpty())
498         return;
499     const LCTYPE types[12] = {
500         LOCALE_SMONTHNAME1,
501         LOCALE_SMONTHNAME2,
502         LOCALE_SMONTHNAME3,
503         LOCALE_SMONTHNAME4,
504         LOCALE_SMONTHNAME5,
505         LOCALE_SMONTHNAME6,
506         LOCALE_SMONTHNAME7,
507         LOCALE_SMONTHNAME8,
508         LOCALE_SMONTHNAME9,
509         LOCALE_SMONTHNAME10,
510         LOCALE_SMONTHNAME11,
511         LOCALE_SMONTHNAME12,
512     };
513     m_monthLabels.reserveCapacity(WTF_ARRAY_LENGTH(types));
514     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(types); ++i) {
515         m_monthLabels.append(getLocaleInfoString(types[i]));
516         if (m_monthLabels.last().isEmpty()) {
517             m_monthLabels.shrink(0);
518             m_monthLabels.reserveCapacity(WTF_ARRAY_LENGTH(WTF::monthFullName));
519             for (unsigned m = 0; m < WTF_ARRAY_LENGTH(WTF::monthFullName); ++m)
520                 m_monthLabels.append(WTF::monthFullName[m]);
521             return;
522         }
523     }
524 }
525
526 void LocaleWin::ensureWeekDayShortLabels()
527 {
528     if (!m_weekDayShortLabels.isEmpty())
529         return;
530     const LCTYPE types[7] = {
531         LOCALE_SABBREVDAYNAME7, // Sunday
532         LOCALE_SABBREVDAYNAME1, // Monday
533         LOCALE_SABBREVDAYNAME2,
534         LOCALE_SABBREVDAYNAME3,
535         LOCALE_SABBREVDAYNAME4,
536         LOCALE_SABBREVDAYNAME5,
537         LOCALE_SABBREVDAYNAME6
538     };
539     m_weekDayShortLabels.reserveCapacity(WTF_ARRAY_LENGTH(types));
540     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(types); ++i) {
541         m_weekDayShortLabels.append(getLocaleInfoString(types[i]));
542         if (m_weekDayShortLabels.last().isEmpty()) {
543             m_weekDayShortLabels.shrink(0);
544             m_weekDayShortLabels.reserveCapacity(WTF_ARRAY_LENGTH(WTF::weekdayName));
545             for (unsigned w = 0; w < WTF_ARRAY_LENGTH(WTF::weekdayName); ++w) {
546                 // weekdayName starts with Monday.
547                 m_weekDayShortLabels.append(WTF::weekdayName[(w + 6) % 7]);
548             }
549             return;
550         }
551     }
552 }
553
554 #if ENABLE(CALENDAR_PICKER) || ENABLE(INPUT_MULTIPLE_FIELDS_UI)
555 const Vector<String>& LocaleWin::monthLabels()
556 {
557     ensureMonthLabels();
558     return m_monthLabels;
559 }
560 #endif
561
562 #if ENABLE(CALENDAR_PICKER)
563 const Vector<String>& LocaleWin::weekDayShortLabels()
564 {
565     ensureWeekDayShortLabels();
566     return m_weekDayShortLabels;
567 }
568
569 unsigned LocaleWin::firstDayOfWeek()
570 {
571     return m_firstDayOfWeek;
572 }
573
574 bool LocaleWin::isRTL()
575 {
576     WTF::Unicode::Direction dir = WTF::Unicode::direction(monthLabels()[0][0]);
577     return dir == WTF::Unicode::RightToLeft || dir == WTF::Unicode::RightToLeftArabic;
578 }
579 #endif
580
581 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
582 static String convertWindowsDateFormatToLDML(const Vector<DateFormatToken>& tokens)
583 {
584     StringBuilder buffer;
585     for (unsigned i = 0; i < tokens.size(); ++i) {
586         switch (tokens[i].type) {
587         case DateFormatToken::Literal:
588             DateTimeFormat::quoteAndAppendLiteral(tokens[i].data, buffer);
589             break;
590
591         case DateFormatToken::Day2:
592             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeDayOfMonth));
593             // Fallthrough.
594         case DateFormatToken::Day1:
595             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeDayOfMonth));
596             break;
597
598         case DateFormatToken::Month4:
599             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeMonth));
600             // Fallthrough.
601         case DateFormatToken::Month3:
602             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeMonth));
603             // Fallthrough.
604         case DateFormatToken::Month2:
605             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeMonth));
606             // Fallthrough.
607         case DateFormatToken::Month1:
608             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeMonth));
609             break;
610
611         case DateFormatToken::Year4:
612             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeYear));
613             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeYear));
614             // Fallthrough.
615         case DateFormatToken::Year2:
616             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeYear));
617             // Fallthrough.
618         case DateFormatToken::Year1:
619             buffer.append(static_cast<char>(DateTimeFormat::FieldTypeYear));
620             break;
621         }
622     }
623     return buffer.toString();
624 }
625
626 static DateTimeFormat::FieldType mapCharacterToDateTimeFieldType(UChar ch)
627 {
628     switch (ch) {
629     case 'h':
630         return DateTimeFormat::FieldTypeHour12;
631
632     case 'H':
633         return DateTimeFormat::FieldTypeHour23;
634
635     case 'm':
636         return DateTimeFormat::FieldTypeMinute;
637
638     case 's':
639         return DateTimeFormat::FieldTypeSecond;
640
641     case 't':
642         return DateTimeFormat::FieldTypePeriod;
643
644     default:
645         return DateTimeFormat::FieldTypeLiteral;
646     }
647 }
648
649 // This class used for converting Windows time pattern format[1] into LDML[2]
650 // time format string.
651 // [1] http://msdn.microsoft.com/en-us/library/windows/desktop/dd318148(v=vs.85).aspx
652 // [2] LDML http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
653 static String convertWindowsTimeFormatToLDML(const String& windowsTimeFormat)
654 {
655     StringBuilder builder;
656     int counter = 0;
657     DateTimeFormat::FieldType lastFieldType = DateTimeFormat::FieldTypeLiteral;
658     for (unsigned index = 0; index < windowsTimeFormat.length(); ++index) {
659         UChar const ch = windowsTimeFormat[index];
660         DateTimeFormat::FieldType fieldType = mapCharacterToDateTimeFieldType(ch);
661         if (fieldType == DateTimeFormat::FieldTypeLiteral)
662             builder.append(ch);
663         else if (fieldType == lastFieldType) {
664             ++counter;
665             if (counter == 2 && lastFieldType != DateTimeFormat::FieldTypePeriod)
666                 builder.append(static_cast<UChar>(lastFieldType));
667         } else {
668             if (lastFieldType != DateTimeFormat::FieldTypeLiteral)
669                 builder.append(static_cast<UChar>(lastFieldType));
670             builder.append(static_cast<UChar>(fieldType));
671             counter = 1;
672         }
673         lastFieldType = fieldType;
674     }
675     return builder.toString();
676 }
677
678 String LocaleWin::dateFormat()
679 {
680     if (!m_dateFormat.isNull())
681         return m_dateFormat;
682     ensureShortDateTokens();
683     m_dateFormat = convertWindowsDateFormatToLDML(m_shortDateTokens);
684     return m_dateFormat;
685 }
686
687 String LocaleWin::dateFormat(const String& windowsFormat)
688 {
689     return convertWindowsDateFormatToLDML(parseDateFormat(windowsFormat));
690 }
691
692 String LocaleWin::monthFormat()
693 {
694     if (!m_monthFormat.isNull())
695         return m_monthFormat;
696     m_monthFormat = convertWindowsDateFormatToLDML(parseDateFormat(getLocaleInfoString(LOCALE_SYEARMONTH)));
697     return m_monthFormat;
698 }
699
700 String LocaleWin::timeFormat()
701 {
702     if (m_timeFormatWithSeconds.isNull())
703         m_timeFormatWithSeconds = convertWindowsTimeFormatToLDML(getLocaleInfoString(LOCALE_STIMEFORMAT));
704     return m_timeFormatWithSeconds;
705 }
706
707 String LocaleWin::shortTimeFormat()
708 {
709     if (!m_timeFormatWithoutSeconds.isNull())
710         return m_timeFormatWithoutSeconds;
711     String format = getLocaleInfoString(LOCALE_SSHORTTIME);
712     // Vista or older Windows doesn't support LOCALE_SSHORTTIME.
713     if (format.isEmpty()) {
714         format = timeFormat();
715         StringBuilder builder;
716         builder.append(getLocaleInfoString(LOCALE_STIME));
717         builder.append("ss");
718         size_t pos = format.reverseFind(builder.toString());
719         if (pos != notFound)
720             format.remove(pos, builder.length());
721     }
722     m_timeFormatWithoutSeconds = convertWindowsTimeFormatToLDML(format);
723     return m_timeFormatWithoutSeconds;
724 }
725
726 const Vector<String>& LocaleWin::shortMonthLabels()
727 {
728     ensureShortMonthLabels();
729     return m_shortMonthLabels;
730 }
731
732 const Vector<String>& LocaleWin::standAloneMonthLabels()
733 {
734     // Windows doesn't provide a way to get stand-alone month labels.
735     return monthLabels();
736 }
737
738 const Vector<String>& LocaleWin::shortStandAloneMonthLabels()
739 {
740     // Windows doesn't provide a way to get stand-alone month labels.
741     return shortMonthLabels();
742 }
743
744 const Vector<String>& LocaleWin::timeAMPMLabels()
745 {
746     if (m_timeAMPMLabels.isEmpty()) {
747         m_timeAMPMLabels.append(getLocaleInfoString(LOCALE_S1159));
748         m_timeAMPMLabels.append(getLocaleInfoString(LOCALE_S2359));
749     }
750     return m_timeAMPMLabels;
751 }
752 #endif
753
754 void LocaleWin::initializeLocaleData()
755 {
756     if (m_didInitializeNumberData)
757         return;
758
759     Vector<String, DecimalSymbolsSize> symbols;
760     enum DigitSubstitution {
761         DigitSubstitutionContext = 0,
762         DigitSubstitution0to9 = 1,
763         DigitSubstitutionNative = 2,
764     };
765     DWORD digitSubstitution = DigitSubstitution0to9;
766     getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, digitSubstitution);
767     if (digitSubstitution == DigitSubstitution0to9) {
768         symbols.append("0");
769         symbols.append("1");
770         symbols.append("2");
771         symbols.append("3");
772         symbols.append("4");
773         symbols.append("5");
774         symbols.append("6");
775         symbols.append("7");
776         symbols.append("8");
777         symbols.append("9");
778     } else {
779         String digits = getLocaleInfoString(LOCALE_SNATIVEDIGITS);
780         ASSERT(digits.length() >= 10);
781         for (unsigned i = 0; i < 10; ++i)
782             symbols.append(digits.substring(i, 1));
783     }
784     ASSERT(symbols.size() == DecimalSeparatorIndex);
785     symbols.append(getLocaleInfoString(LOCALE_SDECIMAL));
786     ASSERT(symbols.size() == GroupSeparatorIndex);
787     symbols.append(getLocaleInfoString(LOCALE_STHOUSAND));
788     ASSERT(symbols.size() == DecimalSymbolsSize);
789
790     String negativeSign = getLocaleInfoString(LOCALE_SNEGATIVESIGN);
791     enum NegativeFormat {
792         NegativeFormatParenthesis = 0,
793         NegativeFormatSignPrefix = 1,
794         NegativeFormatSignSpacePrefix = 2,
795         NegativeFormatSignSuffix = 3,
796         NegativeFormatSpaceSignSuffix = 4,
797     };
798     DWORD negativeFormat = NegativeFormatSignPrefix;
799     getLocaleInfo(LOCALE_INEGNUMBER, negativeFormat);
800     String negativePrefix = emptyString();
801     String negativeSuffix = emptyString();
802     switch (negativeFormat) {
803     case NegativeFormatParenthesis:
804         negativePrefix = "(";
805         negativeSuffix = ")";
806         break;
807     case NegativeFormatSignSpacePrefix:
808         negativePrefix = negativeSign + " ";
809         break;
810     case NegativeFormatSignSuffix:
811         negativeSuffix = negativeSign;
812         break;
813     case NegativeFormatSpaceSignSuffix:
814         negativeSuffix = " " + negativeSign;
815         break;
816     case NegativeFormatSignPrefix: // Fall through.
817     default:
818         negativePrefix = negativeSign;
819         break;
820     }
821     m_didInitializeNumberData = true;
822     setLocaleData(symbols, emptyString(), emptyString(), negativePrefix, negativeSuffix);
823 }
824
825 }