Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / platform / text / LocaleICU.cpp
1 /*
2  * Copyright (C) 2011,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 "LocaleICU.h"
33
34 #include "LocalizedStrings.h"
35 #include <limits>
36 #include <unicode/udatpg.h>
37 #include <unicode/uloc.h>
38 #include <wtf/DateMath.h>
39 #include <wtf/text/StringBuilder.h>
40
41 using namespace icu;
42 using namespace std;
43
44 namespace WebCore {
45
46 std::unique_ptr<Locale> Locale::create(const AtomicString& locale)
47 {
48     return std::make_unique<LocaleICU>(locale.string().utf8().data());
49 }
50
51 LocaleICU::LocaleICU(const char* locale)
52     : m_locale(locale)
53     , m_numberFormat(0)
54     , m_shortDateFormat(0)
55     , m_didCreateDecimalFormat(false)
56     , m_didCreateShortDateFormat(false)
57 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
58     , m_mediumTimeFormat(0)
59     , m_shortTimeFormat(0)
60     , m_didCreateTimeFormat(false)
61 #endif
62 {
63 }
64
65 LocaleICU::~LocaleICU()
66 {
67     unum_close(m_numberFormat);
68     udat_close(m_shortDateFormat);
69 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
70     udat_close(m_mediumTimeFormat);
71     udat_close(m_shortTimeFormat);
72 #endif
73 }
74
75 String LocaleICU::decimalSymbol(UNumberFormatSymbol symbol)
76 {
77     UErrorCode status = U_ZERO_ERROR;
78     int32_t bufferLength = unum_getSymbol(m_numberFormat, symbol, 0, 0, &status);
79     ASSERT(U_SUCCESS(status) || status == U_BUFFER_OVERFLOW_ERROR);
80     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
81         return String();
82     Vector<UChar> buffer(bufferLength);
83     status = U_ZERO_ERROR;
84     unum_getSymbol(m_numberFormat, symbol, buffer.data(), bufferLength, &status);
85     if (U_FAILURE(status))
86         return String();
87     return String::adopt(buffer);
88 }
89
90 String LocaleICU::decimalTextAttribute(UNumberFormatTextAttribute tag)
91 {
92     UErrorCode status = U_ZERO_ERROR;
93     int32_t bufferLength = unum_getTextAttribute(m_numberFormat, tag, 0, 0, &status);
94     ASSERT(U_SUCCESS(status) || status == U_BUFFER_OVERFLOW_ERROR);
95     if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR)
96         return String();
97     Vector<UChar> buffer(bufferLength);
98     status = U_ZERO_ERROR;
99     unum_getTextAttribute(m_numberFormat, tag, buffer.data(), bufferLength, &status);
100     ASSERT(U_SUCCESS(status));
101     if (U_FAILURE(status))
102         return String();
103     return String::adopt(buffer);
104 }
105
106 void LocaleICU::initializeLocaleData()
107 {
108     if (m_didCreateDecimalFormat)
109         return;
110     m_didCreateDecimalFormat = true;
111     UErrorCode status = U_ZERO_ERROR;
112     m_numberFormat = unum_open(UNUM_DECIMAL, 0, 0, m_locale.data(), 0, &status);
113     if (!U_SUCCESS(status))
114         return;
115
116     Vector<String, DecimalSymbolsSize> symbols;
117     symbols.append(decimalSymbol(UNUM_ZERO_DIGIT_SYMBOL));
118     symbols.append(decimalSymbol(UNUM_ONE_DIGIT_SYMBOL));
119     symbols.append(decimalSymbol(UNUM_TWO_DIGIT_SYMBOL));
120     symbols.append(decimalSymbol(UNUM_THREE_DIGIT_SYMBOL));
121     symbols.append(decimalSymbol(UNUM_FOUR_DIGIT_SYMBOL));
122     symbols.append(decimalSymbol(UNUM_FIVE_DIGIT_SYMBOL));
123     symbols.append(decimalSymbol(UNUM_SIX_DIGIT_SYMBOL));
124     symbols.append(decimalSymbol(UNUM_SEVEN_DIGIT_SYMBOL));
125     symbols.append(decimalSymbol(UNUM_EIGHT_DIGIT_SYMBOL));
126     symbols.append(decimalSymbol(UNUM_NINE_DIGIT_SYMBOL));
127     symbols.append(decimalSymbol(UNUM_DECIMAL_SEPARATOR_SYMBOL));
128     symbols.append(decimalSymbol(UNUM_GROUPING_SEPARATOR_SYMBOL));
129     ASSERT(symbols.size() == DecimalSymbolsSize);
130     setLocaleData(symbols, decimalTextAttribute(UNUM_POSITIVE_PREFIX), decimalTextAttribute(UNUM_POSITIVE_SUFFIX), decimalTextAttribute(UNUM_NEGATIVE_PREFIX), decimalTextAttribute(UNUM_NEGATIVE_SUFFIX));
131 }
132
133 bool LocaleICU::initializeShortDateFormat()
134 {
135     if (m_didCreateShortDateFormat)
136         return m_shortDateFormat;
137     m_shortDateFormat = openDateFormat(UDAT_NONE, UDAT_SHORT);
138     m_didCreateShortDateFormat = true;
139     return m_shortDateFormat;
140 }
141
142 UDateFormat* LocaleICU::openDateFormat(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle) const
143 {
144     const UChar gmtTimezone[3] = {'G', 'M', 'T'};
145     UErrorCode status = U_ZERO_ERROR;
146     return udat_open(timeStyle, dateStyle, m_locale.data(), gmtTimezone, WTF_ARRAY_LENGTH(gmtTimezone), 0, -1, &status);
147 }
148
149 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
150 static String getDateFormatPattern(const UDateFormat* dateFormat)
151 {
152     if (!dateFormat)
153         return emptyString();
154
155     UErrorCode status = U_ZERO_ERROR;
156     int32_t length = udat_toPattern(dateFormat, TRUE, 0, 0, &status);
157     if (status != U_BUFFER_OVERFLOW_ERROR || !length)
158         return emptyString();
159     Vector<UChar> buffer(length);
160     status = U_ZERO_ERROR;
161     udat_toPattern(dateFormat, TRUE, buffer.data(), length, &status);
162     if (U_FAILURE(status))
163         return emptyString();
164     return String::adopt(buffer);
165 }
166
167 std::unique_ptr<Vector<String>> LocaleICU::createLabelVector(const UDateFormat* dateFormat, UDateFormatSymbolType type, int32_t startIndex, int32_t size)
168 {
169     if (!dateFormat)
170         return std::make_unique<Vector<String>>();
171     if (udat_countSymbols(dateFormat, type) != startIndex + size)
172         return std::make_unique<Vector<String>>();
173
174     auto labels = std::make_unique<Vector<String>>();
175     labels->reserveCapacity(size);
176     for (int32_t i = 0; i < size; ++i) {
177         UErrorCode status = U_ZERO_ERROR;
178         int32_t length = udat_getSymbols(dateFormat, type, startIndex + i, 0, 0, &status);
179         if (status != U_BUFFER_OVERFLOW_ERROR)
180             return std::make_unique<Vector<String>>();
181         Vector<UChar> buffer(length);
182         status = U_ZERO_ERROR;
183         udat_getSymbols(dateFormat, type, startIndex + i, buffer.data(), length, &status);
184         if (U_FAILURE(status))
185             return std::make_unique<Vector<String>>();
186         labels->append(String::adopt(buffer));
187     }
188     return WTFMove(labels);
189 }
190 #endif
191
192 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
193 static std::unique_ptr<Vector<String>> createFallbackMonthLabels()
194 {
195     auto labels = std::make_unique<Vector<String>>();
196     labels->reserveCapacity(WTF_ARRAY_LENGTH(WTF::monthFullName));
197     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(WTF::monthFullName); ++i)
198         labels->append(WTF::monthFullName[i]);
199     return WTFMove(labels);
200 }
201
202 const Vector<String>& LocaleICU::monthLabels()
203 {
204     if (m_monthLabels)
205         return *m_monthLabels;
206     if (initializeShortDateFormat()) {
207         m_monthLabels = createLabelVector(m_shortDateFormat, UDAT_MONTHS, UCAL_JANUARY, 12);
208         if (m_monthLabels)
209             return *m_monthLabels;
210     }
211     m_monthLabels = createFallbackMonthLabels();
212     return *m_monthLabels;
213 }
214 #endif
215
216 #if ENABLE(DATE_AND_TIME_INPUT_TYPES)
217 static std::unique_ptr<Vector<String>> createFallbackAMPMLabels()
218 {
219     auto labels = std::make_unique<Vector<String>>();
220     labels->reserveCapacity(2);
221     labels->append("AM");
222     labels->append("PM");
223     return WTFMove(labels);
224 }
225
226 void LocaleICU::initializeDateTimeFormat()
227 {
228     if (m_didCreateTimeFormat)
229         return;
230
231     // We assume ICU medium time pattern and short time pattern are compatible
232     // with LDML, because ICU specific pattern character "V" doesn't appear
233     // in both medium and short time pattern.
234     m_mediumTimeFormat = openDateFormat(UDAT_MEDIUM, UDAT_NONE);
235     m_timeFormatWithSeconds = getDateFormatPattern(m_mediumTimeFormat);
236
237     m_shortTimeFormat = openDateFormat(UDAT_SHORT, UDAT_NONE);
238     m_timeFormatWithoutSeconds = getDateFormatPattern(m_shortTimeFormat);
239
240     UDateFormat* dateTimeFormatWithSeconds = openDateFormat(UDAT_MEDIUM, UDAT_SHORT);
241     m_dateTimeFormatWithSeconds = getDateFormatPattern(dateTimeFormatWithSeconds);
242     udat_close(dateTimeFormatWithSeconds);
243
244     UDateFormat* dateTimeFormatWithoutSeconds = openDateFormat(UDAT_SHORT, UDAT_SHORT);
245     m_dateTimeFormatWithoutSeconds = getDateFormatPattern(dateTimeFormatWithoutSeconds);
246     udat_close(dateTimeFormatWithoutSeconds);
247
248     auto timeAMPMLabels = createLabelVector(m_mediumTimeFormat, UDAT_AM_PMS, UCAL_AM, 2);
249     if (!timeAMPMLabels)
250         timeAMPMLabels = createFallbackAMPMLabels();
251     m_timeAMPMLabels = *timeAMPMLabels;
252
253     m_didCreateTimeFormat = true;
254 }
255
256 String LocaleICU::dateFormat()
257 {
258     if (!m_dateFormat.isNull())
259         return m_dateFormat;
260     if (!initializeShortDateFormat())
261         return ASCIILiteral("yyyy-MM-dd");
262     m_dateFormat = getDateFormatPattern(m_shortDateFormat);
263     return m_dateFormat;
264 }
265
266 static String getFormatForSkeleton(const char* locale, const String& skeleton)
267 {
268     String format = ASCIILiteral("yyyy-MM");
269     UErrorCode status = U_ZERO_ERROR;
270     UDateTimePatternGenerator* patternGenerator = udatpg_open(locale, &status);
271     if (!patternGenerator)
272         return format;
273     status = U_ZERO_ERROR;
274     int32_t length = udatpg_getBestPattern(patternGenerator, skeleton.characters(), skeleton.length(), 0, 0, &status);
275     if (status == U_BUFFER_OVERFLOW_ERROR && length) {
276         Vector<UChar> buffer(length);
277         status = U_ZERO_ERROR;
278         udatpg_getBestPattern(patternGenerator, skeleton.characters(), skeleton.length(), buffer.data(), length, &status);
279         if (U_SUCCESS(status))
280             format = String::adopt(buffer);
281     }
282     udatpg_close(patternGenerator);
283     return format;
284 }
285
286 String LocaleICU::monthFormat()
287 {
288     if (!m_monthFormat.isNull())
289         return m_monthFormat;
290     // Gets a format for "MMMM" because Windows API always provides formats for
291     // "MMMM" in some locales.
292     m_monthFormat = getFormatForSkeleton(m_locale.data(), ASCIILiteral("yyyyMMMM"));
293     return m_monthFormat;
294 }
295
296 String LocaleICU::shortMonthFormat()
297 {
298     if (!m_shortMonthFormat.isNull())
299         return m_shortMonthFormat;
300     m_shortMonthFormat = getFormatForSkeleton(m_locale.data(), ASCIILiteral("yyyyMMM"));
301     return m_shortMonthFormat;
302 }
303
304 String LocaleICU::timeFormat()
305 {
306     initializeDateTimeFormat();
307     return m_timeFormatWithSeconds;
308 }
309
310 String LocaleICU::shortTimeFormat()
311 {
312     initializeDateTimeFormat();
313     return m_timeFormatWithoutSeconds;
314 }
315
316 String LocaleICU::dateTimeFormatWithSeconds()
317 {
318     initializeDateTimeFormat();
319     return m_dateTimeFormatWithSeconds;
320 }
321
322 String LocaleICU::dateTimeFormatWithoutSeconds()
323 {
324     initializeDateTimeFormat();
325     return m_dateTimeFormatWithoutSeconds;
326 }
327
328 const Vector<String>& LocaleICU::shortMonthLabels()
329 {
330     if (!m_shortMonthLabels.isEmpty())
331         return m_shortMonthLabels;
332     if (initializeShortDateFormat()) {
333         if (auto labels = createLabelVector(m_shortDateFormat, UDAT_SHORT_MONTHS, UCAL_JANUARY, 12)) {
334             m_shortMonthLabels = *labels;
335             return m_shortMonthLabels;
336         }
337     }
338     m_shortMonthLabels.reserveCapacity(WTF_ARRAY_LENGTH(WTF::monthName));
339     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(WTF::monthName); ++i)
340         m_shortMonthLabels.append(WTF::monthName[i]);
341     return m_shortMonthLabels;
342 }
343
344 const Vector<String>& LocaleICU::standAloneMonthLabels()
345 {
346     if (!m_standAloneMonthLabels.isEmpty())
347         return m_standAloneMonthLabels;
348     if (initializeShortDateFormat()) {
349         if (auto labels = createLabelVector(m_shortDateFormat, UDAT_STANDALONE_MONTHS, UCAL_JANUARY, 12)) {
350             m_standAloneMonthLabels = *labels;
351             return m_standAloneMonthLabels;
352         }
353     }
354     m_standAloneMonthLabels = monthLabels();
355     return m_standAloneMonthLabels;
356 }
357
358 const Vector<String>& LocaleICU::shortStandAloneMonthLabels()
359 {
360     if (!m_shortStandAloneMonthLabels.isEmpty())
361         return m_shortStandAloneMonthLabels;
362     if (initializeShortDateFormat()) {
363         if (auto labels = createLabelVector(m_shortDateFormat, UDAT_STANDALONE_SHORT_MONTHS, UCAL_JANUARY, 12)) {
364             m_shortStandAloneMonthLabels = *labels;
365             return m_shortStandAloneMonthLabels;
366         }
367     }
368     m_shortStandAloneMonthLabels = shortMonthLabels();
369     return m_shortStandAloneMonthLabels;
370 }
371
372 const Vector<String>& LocaleICU::timeAMPMLabels()
373 {
374     initializeDateTimeFormat();
375     return m_timeAMPMLabels;
376 }
377
378 #endif
379
380 } // namespace WebCore
381