[WTF] Move currentCPUTime and sleep(Seconds) to CPUTime.h and Seconds.h respectively
[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 #include "DateTimeFormat.h"
36 #include "LocalizedStrings.h"
37 #include <limits>
38 #include <windows.h>
39 #include <wtf/DateMath.h>
40 #include <wtf/HashMap.h>
41 #include <wtf/Language.h>
42 #include <wtf/text/StringBuilder.h>
43 #include <wtf/text/StringHash.h>
44 #include <wtf/text/win/WCharStringExtras.h>
45
46 namespace WebCore {
47 using namespace std;
48
49 typedef HashMap<String, LCID, ASCIICaseInsensitiveHash> NameToLCIDMap;
50
51 static String extractLanguageCode(const String& locale)
52 {
53     size_t dashPosition = locale.find('-');
54     if (dashPosition == notFound)
55         return locale;
56     return locale.left(dashPosition);
57 }
58
59 static LCID LCIDFromLocaleInternal(LCID userDefaultLCID, const String& userDefaultLanguageCode, const String& locale)
60 {
61     if (equalIgnoringASCIICase(extractLanguageCode(locale), userDefaultLanguageCode))
62         return userDefaultLCID;
63     return LocaleNameToLCID(stringToNullTerminatedWChar(locale).data(), 0);
64 }
65
66 static LCID LCIDFromLocale(const AtomicString& locale)
67 {
68     // According to MSDN, 9 is enough for LOCALE_SISO639LANGNAME.
69     const size_t languageCodeBufferSize = 9;
70     WCHAR lowercaseLanguageCode[languageCodeBufferSize];
71     ::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lowercaseLanguageCode, languageCodeBufferSize);
72     String userDefaultLanguageCode = nullTerminatedWCharToString(lowercaseLanguageCode);
73
74     LCID lcid = LCIDFromLocaleInternal(LOCALE_USER_DEFAULT, userDefaultLanguageCode, String(locale));
75     if (!lcid)
76         lcid = LCIDFromLocaleInternal(LOCALE_USER_DEFAULT, userDefaultLanguageCode, defaultLanguage());
77     return lcid;
78 }
79
80 std::unique_ptr<Locale> Locale::create(const AtomicString& locale)
81 {
82     return std::make_unique<LocaleWin>(LCIDFromLocale(locale));
83 }
84
85 inline LocaleWin::LocaleWin(LCID lcid)
86     : m_lcid(lcid)
87     , m_didInitializeNumberData(false)
88 {
89 }
90
91 LocaleWin::~LocaleWin() = default;
92
93 String LocaleWin::getLocaleInfoString(LCTYPE type)
94 {
95     int bufferSizeWithNUL = ::GetLocaleInfo(m_lcid, type, 0, 0);
96     if (bufferSizeWithNUL <= 0)
97         return String();
98     StringVector<UChar> buffer(bufferSizeWithNUL);
99     ::GetLocaleInfo(m_lcid, type, buffer.data(), bufferSizeWithNUL);
100     buffer.shrink(bufferSizeWithNUL - 1);
101     return String::adopt(WTFMove(buffer));
102 }
103
104 void LocaleWin::getLocaleInfo(LCTYPE type, DWORD& result)
105 {
106     ::GetLocaleInfo(m_lcid, type | LOCALE_RETURN_NUMBER, reinterpret_cast<LPWSTR>(&result), sizeof(DWORD) / sizeof(TCHAR));
107 }
108
109 void LocaleWin::ensureShortMonthLabels()
110 {
111 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
112     if (!m_shortMonthLabels.isEmpty())
113         return;
114     const LCTYPE types[12] = {
115         LOCALE_SABBREVMONTHNAME1,
116         LOCALE_SABBREVMONTHNAME2,
117         LOCALE_SABBREVMONTHNAME3,
118         LOCALE_SABBREVMONTHNAME4,
119         LOCALE_SABBREVMONTHNAME5,
120         LOCALE_SABBREVMONTHNAME6,
121         LOCALE_SABBREVMONTHNAME7,
122         LOCALE_SABBREVMONTHNAME8,
123         LOCALE_SABBREVMONTHNAME9,
124         LOCALE_SABBREVMONTHNAME10,
125         LOCALE_SABBREVMONTHNAME11,
126         LOCALE_SABBREVMONTHNAME12,
127     };
128     m_shortMonthLabels.reserveCapacity(WTF_ARRAY_LENGTH(types));
129     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(types); ++i) {
130         m_shortMonthLabels.append(getLocaleInfoString(types[i]));
131         if (m_shortMonthLabels.last().isEmpty()) {
132             m_shortMonthLabels.shrink(0);
133             m_shortMonthLabels.reserveCapacity(WTF_ARRAY_LENGTH(WTF::monthName));
134             for (unsigned m = 0; m < WTF_ARRAY_LENGTH(WTF::monthName); ++m)
135                 m_shortMonthLabels.append(WTF::monthName[m]);
136             return;
137         }
138     }
139 #endif
140 }
141
142 // -------------------------------- Tokenized date format
143
144 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
145 static unsigned countContinuousLetters(const String& format, unsigned index)
146 {
147     unsigned count = 1;
148     UChar reference = format[index];
149     while (index + 1 < format.length()) {
150         if (format[++index] != reference)
151             break;
152         ++count;
153     }
154     return count;
155 }
156
157 static void commitLiteralToken(StringBuilder& literalBuffer, StringBuilder& converted)
158 {
159     if (literalBuffer.length() <= 0)
160         return;
161     DateTimeFormat::quoteAndAppendLiteral(literalBuffer.toString(), converted);
162     literalBuffer.clear();
163 }
164
165 // This function converts Windows date/time pattern format [1][2] into LDML date
166 // format pattern [3].
167 //
168 // i.e.
169 //   We set h, H, m, s, d, dd, M, or y as is. They have same meaning in both of
170 //   Windows and LDML.
171 //   We need to convert the following patterns:
172 //     t -> a
173 //     tt -> a
174 //     ddd -> EEE
175 //     dddd -> EEEE
176 //     g -> G
177 //     gg -> ignore
178 //
179 // [1] http://msdn.microsoft.com/en-us/library/dd317787(v=vs.85).aspx
180 // [2] http://msdn.microsoft.com/en-us/library/dd318148(v=vs.85).aspx
181 // [3] LDML http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
182 static String convertWindowsDateTimeFormat(const String& format)
183 {
184     StringBuilder converted;
185     StringBuilder literalBuffer;
186     bool inQuote = false;
187     bool lastQuoteCanBeLiteral = false;
188     for (unsigned i = 0; i < format.length(); ++i) {
189         UChar ch = format[i];
190         if (inQuote) {
191             if (ch == '\'') {
192                 inQuote = false;
193                 ASSERT(i);
194                 if (lastQuoteCanBeLiteral && format[i - 1] == '\'') {
195                     literalBuffer.append('\'');
196                     lastQuoteCanBeLiteral = false;
197                 } else
198                     lastQuoteCanBeLiteral = true;
199             } else
200                 literalBuffer.append(ch);
201             continue;
202         }
203
204         if (ch == '\'') {
205             inQuote = true;
206             if (lastQuoteCanBeLiteral && i > 0 && format[i - 1] == '\'') {
207                 literalBuffer.append(ch);
208                 lastQuoteCanBeLiteral = false;
209             } else
210                 lastQuoteCanBeLiteral = true;
211         } else if (isASCIIAlpha(ch)) {
212             commitLiteralToken(literalBuffer, converted);
213             unsigned symbolStart = i;
214             unsigned count = countContinuousLetters(format, i);
215             i += count - 1;
216             if (ch == 'h' || ch == 'H' || ch == 'm' || ch == 's' || ch == 'M' || ch == 'y')
217                 converted.append(format, symbolStart, count);
218             else if (ch == 'd') {
219                 if (count <= 2)
220                     converted.append(format, symbolStart, count);
221                 else if (count == 3)
222                     converted.append("EEE");
223                 else
224                     converted.append("EEEE");
225             } else if (ch == 'g') {
226                 if (count == 1)
227                     converted.append('G');
228                 else {
229                     // gg means imperial era in Windows.
230                     // Just ignore it.
231                 }
232             } else if (ch == 't')
233                 converted.append('a');
234             else
235                 literalBuffer.append(format, symbolStart, count);
236         } else
237             literalBuffer.append(ch);
238     }
239     commitLiteralToken(literalBuffer, converted);
240     return converted.toString();
241 }
242 #endif
243
244 void LocaleWin::ensureMonthLabels()
245 {
246 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
247     if (!m_monthLabels.isEmpty())
248         return;
249     const LCTYPE types[12] = {
250         LOCALE_SMONTHNAME1,
251         LOCALE_SMONTHNAME2,
252         LOCALE_SMONTHNAME3,
253         LOCALE_SMONTHNAME4,
254         LOCALE_SMONTHNAME5,
255         LOCALE_SMONTHNAME6,
256         LOCALE_SMONTHNAME7,
257         LOCALE_SMONTHNAME8,
258         LOCALE_SMONTHNAME9,
259         LOCALE_SMONTHNAME10,
260         LOCALE_SMONTHNAME11,
261         LOCALE_SMONTHNAME12,
262     };
263     m_monthLabels.reserveCapacity(WTF_ARRAY_LENGTH(types));
264     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(types); ++i) {
265         m_monthLabels.append(getLocaleInfoString(types[i]));
266         if (m_monthLabels.last().isEmpty()) {
267             m_monthLabels.shrink(0);
268             m_monthLabels.reserveCapacity(WTF_ARRAY_LENGTH(WTF::monthFullName));
269             for (unsigned m = 0; m < WTF_ARRAY_LENGTH(WTF::monthFullName); ++m)
270                 m_monthLabels.append(WTF::monthFullName[m]);
271             return;
272         }
273     }
274 #endif
275 }
276
277 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
278 const Vector<String>& LocaleWin::monthLabels()
279 {
280     ensureMonthLabels();
281     return m_monthLabels;
282 }
283
284 String LocaleWin::dateFormat()
285 {
286     if (m_dateFormat.isNull())
287         m_dateFormat = convertWindowsDateTimeFormat(getLocaleInfoString(LOCALE_SSHORTDATE));
288     return m_dateFormat;
289 }
290
291 String LocaleWin::dateFormat(const String& windowsFormat)
292 {
293     return convertWindowsDateTimeFormat(windowsFormat);
294 }
295
296 String LocaleWin::monthFormat()
297 {
298     if (m_monthFormat.isNull())
299         m_monthFormat = convertWindowsDateTimeFormat(getLocaleInfoString(LOCALE_SYEARMONTH));
300     return m_monthFormat;
301 }
302
303 String LocaleWin::shortMonthFormat()
304 {
305     if (m_shortMonthFormat.isNull())
306         m_shortMonthFormat = convertWindowsDateTimeFormat(getLocaleInfoString(LOCALE_SYEARMONTH)).replace("MMMM", "MMM");
307     return m_shortMonthFormat;
308 }
309
310 String LocaleWin::timeFormat()
311 {
312     if (m_timeFormatWithSeconds.isNull())
313         m_timeFormatWithSeconds = convertWindowsDateTimeFormat(getLocaleInfoString(LOCALE_STIMEFORMAT));
314     return m_timeFormatWithSeconds;
315 }
316
317 String LocaleWin::shortTimeFormat()
318 {
319     if (!m_timeFormatWithoutSeconds.isNull())
320         return m_timeFormatWithoutSeconds;
321     String format = getLocaleInfoString(LOCALE_SSHORTTIME);
322     // Vista or older Windows doesn't support LOCALE_SSHORTTIME.
323     if (format.isEmpty()) {
324         format = getLocaleInfoString(LOCALE_STIMEFORMAT);
325         StringBuilder builder;
326         builder.append(getLocaleInfoString(LOCALE_STIME));
327         builder.append("ss");
328         size_t pos = format.reverseFind(builder.toString());
329         if (pos != notFound)
330             format.remove(pos, builder.length());
331     }
332     m_timeFormatWithoutSeconds = convertWindowsDateTimeFormat(format);
333     return m_timeFormatWithoutSeconds;
334 }
335
336 String LocaleWin::dateTimeFormatWithSeconds()
337 {
338     if (!m_dateTimeFormatWithSeconds.isNull())
339         return m_dateTimeFormatWithSeconds;
340     StringBuilder builder;
341     builder.append(dateFormat());
342     builder.append(' ');
343     builder.append(timeFormat());
344     m_dateTimeFormatWithSeconds = builder.toString();
345     return m_dateTimeFormatWithSeconds;
346 }
347
348 String LocaleWin::dateTimeFormatWithoutSeconds()
349 {
350     if (!m_dateTimeFormatWithoutSeconds.isNull())
351         return m_dateTimeFormatWithoutSeconds;
352     StringBuilder builder;
353     builder.append(dateFormat());
354     builder.append(' ');
355     builder.append(shortTimeFormat());
356     m_dateTimeFormatWithoutSeconds = builder.toString();
357     return m_dateTimeFormatWithoutSeconds;
358 }
359
360 const Vector<String>& LocaleWin::shortMonthLabels()
361 {
362     ensureShortMonthLabels();
363     return m_shortMonthLabels;
364 }
365
366 const Vector<String>& LocaleWin::standAloneMonthLabels()
367 {
368     // Windows doesn't provide a way to get stand-alone month labels.
369     return monthLabels();
370 }
371
372 const Vector<String>& LocaleWin::shortStandAloneMonthLabels()
373 {
374     // Windows doesn't provide a way to get stand-alone month labels.
375     return shortMonthLabels();
376 }
377
378 const Vector<String>& LocaleWin::timeAMPMLabels()
379 {
380     if (m_timeAMPMLabels.isEmpty()) {
381         m_timeAMPMLabels.append(getLocaleInfoString(LOCALE_S1159));
382         m_timeAMPMLabels.append(getLocaleInfoString(LOCALE_S2359));
383     }
384     return m_timeAMPMLabels;
385 }
386 #endif
387
388 void LocaleWin::initializeLocaleData()
389 {
390     if (m_didInitializeNumberData)
391         return;
392
393     Vector<String, DecimalSymbolsSize> symbols;
394     enum DigitSubstitution {
395         DigitSubstitutionContext = 0,
396         DigitSubstitution0to9 = 1,
397         DigitSubstitutionNative = 2,
398     };
399     DWORD digitSubstitution = DigitSubstitution0to9;
400     getLocaleInfo(LOCALE_IDIGITSUBSTITUTION, digitSubstitution);
401     if (digitSubstitution == DigitSubstitution0to9) {
402         symbols.append("0");
403         symbols.append("1");
404         symbols.append("2");
405         symbols.append("3");
406         symbols.append("4");
407         symbols.append("5");
408         symbols.append("6");
409         symbols.append("7");
410         symbols.append("8");
411         symbols.append("9");
412     } else {
413         String digits = getLocaleInfoString(LOCALE_SNATIVEDIGITS);
414         ASSERT(digits.length() >= 10);
415         for (unsigned i = 0; i < 10; ++i)
416             symbols.append(digits.substring(i, 1));
417     }
418     ASSERT(symbols.size() == DecimalSeparatorIndex);
419     symbols.append(getLocaleInfoString(LOCALE_SDECIMAL));
420     ASSERT(symbols.size() == GroupSeparatorIndex);
421     symbols.append(getLocaleInfoString(LOCALE_STHOUSAND));
422     ASSERT(symbols.size() == DecimalSymbolsSize);
423
424     String negativeSign = getLocaleInfoString(LOCALE_SNEGATIVESIGN);
425     enum NegativeFormat {
426         NegativeFormatParenthesis = 0,
427         NegativeFormatSignPrefix = 1,
428         NegativeFormatSignSpacePrefix = 2,
429         NegativeFormatSignSuffix = 3,
430         NegativeFormatSpaceSignSuffix = 4,
431     };
432     DWORD negativeFormat = NegativeFormatSignPrefix;
433     getLocaleInfo(LOCALE_INEGNUMBER, negativeFormat);
434     String negativePrefix = emptyString();
435     String negativeSuffix = emptyString();
436     switch (negativeFormat) {
437     case NegativeFormatParenthesis:
438         negativePrefix = "(";
439         negativeSuffix = ")";
440         break;
441     case NegativeFormatSignSpacePrefix:
442         negativePrefix = negativeSign + " ";
443         break;
444     case NegativeFormatSignSuffix:
445         negativeSuffix = negativeSign;
446         break;
447     case NegativeFormatSpaceSignSuffix:
448         negativeSuffix = " " + negativeSign;
449         break;
450     case NegativeFormatSignPrefix:
451         FALLTHROUGH;
452     default:
453         negativePrefix = negativeSign;
454         break;
455     }
456     m_didInitializeNumberData = true;
457     setLocaleData(symbols, emptyString(), emptyString(), negativePrefix, negativeSuffix);
458 }
459
460 }