Improve use of NeverDestroyed
[WebKit-https.git] / Source / WebCore / platform / text / LocaleToScriptMappingDefault.cpp
1 /*
2  * Copyright (C) 2011 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 "LocaleToScriptMapping.h"
33
34 #include <wtf/HashMap.h>
35 #include <wtf/NeverDestroyed.h>
36 #include <wtf/text/StringHash.h>
37
38 namespace WebCore {
39
40 struct ScriptNameCode {
41     const char* name;
42     UScriptCode code;
43 };
44
45 // This generally maps an ISO 15924 script code to its UScriptCode, but certain families of script codes are
46 // treated as a single script for assigning a per-script font in Settings. For example, "hira" is mapped to
47 // USCRIPT_KATAKANA_OR_HIRAGANA instead of USCRIPT_HIRAGANA, since we want all Japanese scripts to be rendered
48 // using the same font setting.
49 static const ScriptNameCode scriptNameCodeList[] = {
50     { "zyyy", USCRIPT_COMMON },
51     { "qaai", USCRIPT_INHERITED },
52     { "arab", USCRIPT_ARABIC },
53     { "armn", USCRIPT_ARMENIAN },
54     { "beng", USCRIPT_BENGALI },
55     { "bopo", USCRIPT_BOPOMOFO },
56     { "cher", USCRIPT_CHEROKEE },
57     { "copt", USCRIPT_COPTIC },
58     { "cyrl", USCRIPT_CYRILLIC },
59     { "dsrt", USCRIPT_DESERET },
60     { "deva", USCRIPT_DEVANAGARI },
61     { "ethi", USCRIPT_ETHIOPIC },
62     { "geor", USCRIPT_GEORGIAN },
63     { "goth", USCRIPT_GOTHIC },
64     { "grek", USCRIPT_GREEK },
65     { "gujr", USCRIPT_GUJARATI },
66     { "guru", USCRIPT_GURMUKHI },
67     { "hani", USCRIPT_HAN },
68     { "hang", USCRIPT_HANGUL },
69     { "hebr", USCRIPT_HEBREW },
70     { "hira", USCRIPT_KATAKANA_OR_HIRAGANA },
71     { "knda", USCRIPT_KANNADA },
72     { "kana", USCRIPT_KATAKANA_OR_HIRAGANA },
73     { "khmr", USCRIPT_KHMER },
74     { "laoo", USCRIPT_LAO },
75     { "latn", USCRIPT_LATIN },
76     { "mlym", USCRIPT_MALAYALAM },
77     { "mong", USCRIPT_MONGOLIAN },
78     { "mymr", USCRIPT_MYANMAR },
79     { "ogam", USCRIPT_OGHAM },
80     { "ital", USCRIPT_OLD_ITALIC },
81     { "orya", USCRIPT_ORIYA },
82     { "runr", USCRIPT_RUNIC },
83     { "sinh", USCRIPT_SINHALA },
84     { "syrc", USCRIPT_SYRIAC },
85     { "taml", USCRIPT_TAMIL },
86     { "telu", USCRIPT_TELUGU },
87     { "thaa", USCRIPT_THAANA },
88     { "thai", USCRIPT_THAI },
89     { "tibt", USCRIPT_TIBETAN },
90     { "cans", USCRIPT_CANADIAN_ABORIGINAL },
91     { "yiii", USCRIPT_YI },
92     { "tglg", USCRIPT_TAGALOG },
93     { "hano", USCRIPT_HANUNOO },
94     { "buhd", USCRIPT_BUHID },
95     { "tagb", USCRIPT_TAGBANWA },
96     { "brai", USCRIPT_BRAILLE },
97     { "cprt", USCRIPT_CYPRIOT },
98     { "limb", USCRIPT_LIMBU },
99     { "linb", USCRIPT_LINEAR_B },
100     { "osma", USCRIPT_OSMANYA },
101     { "shaw", USCRIPT_SHAVIAN },
102     { "tale", USCRIPT_TAI_LE },
103     { "ugar", USCRIPT_UGARITIC },
104     { "hrkt", USCRIPT_KATAKANA_OR_HIRAGANA },
105     { "bugi", USCRIPT_BUGINESE },
106     { "glag", USCRIPT_GLAGOLITIC },
107     { "khar", USCRIPT_KHAROSHTHI },
108     { "sylo", USCRIPT_SYLOTI_NAGRI },
109     { "talu", USCRIPT_NEW_TAI_LUE },
110     { "tfng", USCRIPT_TIFINAGH },
111     { "xpeo", USCRIPT_OLD_PERSIAN },
112     { "bali", USCRIPT_BALINESE },
113     { "batk", USCRIPT_BATAK },
114     { "blis", USCRIPT_BLISSYMBOLS },
115     { "brah", USCRIPT_BRAHMI },
116     { "cham", USCRIPT_CHAM },
117     { "cirt", USCRIPT_CIRTH },
118     { "cyrs", USCRIPT_OLD_CHURCH_SLAVONIC_CYRILLIC },
119     { "egyd", USCRIPT_DEMOTIC_EGYPTIAN },
120     { "egyh", USCRIPT_HIERATIC_EGYPTIAN },
121     { "egyp", USCRIPT_EGYPTIAN_HIEROGLYPHS },
122     { "geok", USCRIPT_KHUTSURI },
123     { "hans", USCRIPT_SIMPLIFIED_HAN },
124     { "hant", USCRIPT_TRADITIONAL_HAN },
125     { "hmng", USCRIPT_PAHAWH_HMONG },
126     { "hung", USCRIPT_OLD_HUNGARIAN },
127     { "inds", USCRIPT_HARAPPAN_INDUS },
128     { "java", USCRIPT_JAVANESE },
129     { "kali", USCRIPT_KAYAH_LI },
130     { "latf", USCRIPT_LATIN_FRAKTUR },
131     { "latg", USCRIPT_LATIN_GAELIC },
132     { "lepc", USCRIPT_LEPCHA },
133     { "lina", USCRIPT_LINEAR_A },
134     { "mand", USCRIPT_MANDAEAN },
135     { "maya", USCRIPT_MAYAN_HIEROGLYPHS },
136     { "mero", USCRIPT_MEROITIC },
137     { "nkoo", USCRIPT_NKO },
138     { "orkh", USCRIPT_ORKHON },
139     { "perm", USCRIPT_OLD_PERMIC },
140     { "phag", USCRIPT_PHAGS_PA },
141     { "phnx", USCRIPT_PHOENICIAN },
142     { "plrd", USCRIPT_PHONETIC_POLLARD },
143     { "roro", USCRIPT_RONGORONGO },
144     { "sara", USCRIPT_SARATI },
145     { "syre", USCRIPT_ESTRANGELO_SYRIAC },
146     { "syrj", USCRIPT_WESTERN_SYRIAC },
147     { "syrn", USCRIPT_EASTERN_SYRIAC },
148     { "teng", USCRIPT_TENGWAR },
149     { "vaii", USCRIPT_VAI },
150     { "visp", USCRIPT_VISIBLE_SPEECH },
151     { "xsux", USCRIPT_CUNEIFORM },
152     { "jpan", USCRIPT_KATAKANA_OR_HIRAGANA },
153     { "kore", USCRIPT_HANGUL },
154     { "zxxx", USCRIPT_UNWRITTEN_LANGUAGES },
155     { "zzzz", USCRIPT_UNKNOWN }
156 };
157
158 struct ScriptNameCodeMapHashTraits : public HashTraits<String> {
159     static const int minimumTableSize = WTF::HashTableCapacityForSize<WTF_ARRAY_LENGTH(scriptNameCodeList)>::value;
160 };
161
162 UScriptCode scriptNameToCode(const String& scriptName)
163 {
164     static const auto scriptNameCodeMap = makeNeverDestroyed([] {
165         HashMap<String, UScriptCode, ASCIICaseInsensitiveHash, ScriptNameCodeMapHashTraits> map;
166         for (auto& nameAndCode : scriptNameCodeList)
167             map.add(ASCIILiteral(nameAndCode.name), nameAndCode.code);
168         return map;
169     }());
170
171     auto it = scriptNameCodeMap.get().find(scriptName);
172     if (it != scriptNameCodeMap.get().end())
173         return it->value;
174     return USCRIPT_INVALID_CODE;
175 }
176
177 struct LocaleScript {
178     const char* locale;
179     UScriptCode script;
180 };
181
182 static const LocaleScript localeScriptList[] = {
183     { "aa", USCRIPT_LATIN },
184     { "ab", USCRIPT_CYRILLIC },
185     { "ady", USCRIPT_CYRILLIC },
186     { "af", USCRIPT_LATIN },
187     { "ak", USCRIPT_LATIN },
188     { "am", USCRIPT_ETHIOPIC },
189     { "ar", USCRIPT_ARABIC },
190     { "as", USCRIPT_BENGALI },
191     { "ast", USCRIPT_LATIN },
192     { "av", USCRIPT_CYRILLIC },
193     { "ay", USCRIPT_LATIN },
194     { "az", USCRIPT_LATIN },
195     { "ba", USCRIPT_CYRILLIC },
196     { "be", USCRIPT_CYRILLIC },
197     { "bg", USCRIPT_CYRILLIC },
198     { "bi", USCRIPT_LATIN },
199     { "bn", USCRIPT_BENGALI },
200     { "bo", USCRIPT_TIBETAN },
201     { "bs", USCRIPT_LATIN },
202     { "ca", USCRIPT_LATIN },
203     { "ce", USCRIPT_CYRILLIC },
204     { "ceb", USCRIPT_LATIN },
205     { "ch", USCRIPT_LATIN },
206     { "chk", USCRIPT_LATIN },
207     { "cs", USCRIPT_LATIN },
208     { "cy", USCRIPT_LATIN },
209     { "da", USCRIPT_LATIN },
210     { "de", USCRIPT_LATIN },
211     { "dv", USCRIPT_THAANA },
212     { "dz", USCRIPT_TIBETAN },
213     { "ee", USCRIPT_LATIN },
214     { "efi", USCRIPT_LATIN },
215     { "el", USCRIPT_GREEK },
216     { "en", USCRIPT_LATIN },
217     { "es", USCRIPT_LATIN },
218     { "et", USCRIPT_LATIN },
219     { "eu", USCRIPT_LATIN },
220     { "fa", USCRIPT_ARABIC },
221     { "fi", USCRIPT_LATIN },
222     { "fil", USCRIPT_LATIN },
223     { "fj", USCRIPT_LATIN },
224     { "fo", USCRIPT_LATIN },
225     { "fr", USCRIPT_LATIN },
226     { "fur", USCRIPT_LATIN },
227     { "fy", USCRIPT_LATIN },
228     { "ga", USCRIPT_LATIN },
229     { "gaa", USCRIPT_LATIN },
230     { "gd", USCRIPT_LATIN },
231     { "gil", USCRIPT_LATIN },
232     { "gl", USCRIPT_LATIN },
233     { "gn", USCRIPT_LATIN },
234     { "gsw", USCRIPT_LATIN },
235     { "gu", USCRIPT_GUJARATI },
236     { "ha", USCRIPT_LATIN },
237     { "haw", USCRIPT_LATIN },
238     { "he", USCRIPT_HEBREW },
239     { "hi", USCRIPT_DEVANAGARI },
240     { "hil", USCRIPT_LATIN },
241     { "ho", USCRIPT_LATIN },
242     { "hr", USCRIPT_LATIN },
243     { "ht", USCRIPT_LATIN },
244     { "hu", USCRIPT_LATIN },
245     { "hy", USCRIPT_ARMENIAN },
246     { "id", USCRIPT_LATIN },
247     { "ig", USCRIPT_LATIN },
248     { "ii", USCRIPT_YI },
249     { "ilo", USCRIPT_LATIN },
250     { "inh", USCRIPT_CYRILLIC },
251     { "is", USCRIPT_LATIN },
252     { "it", USCRIPT_LATIN },
253     { "iu", USCRIPT_CANADIAN_ABORIGINAL },
254     { "ja", USCRIPT_KATAKANA_OR_HIRAGANA },
255     { "jv", USCRIPT_LATIN },
256     { "ka", USCRIPT_GEORGIAN },
257     { "kaj", USCRIPT_LATIN },
258     { "kam", USCRIPT_LATIN },
259     { "kbd", USCRIPT_CYRILLIC },
260     { "kha", USCRIPT_LATIN },
261     { "kk", USCRIPT_CYRILLIC },
262     { "kl", USCRIPT_LATIN },
263     { "km", USCRIPT_KHMER },
264     { "kn", USCRIPT_KANNADA },
265     { "ko", USCRIPT_HANGUL },
266     { "kok", USCRIPT_DEVANAGARI },
267     { "kos", USCRIPT_LATIN },
268     { "kpe", USCRIPT_LATIN },
269     { "krc", USCRIPT_CYRILLIC },
270     { "ks", USCRIPT_ARABIC },
271     { "ku", USCRIPT_ARABIC },
272     { "kum", USCRIPT_CYRILLIC },
273     { "ky", USCRIPT_CYRILLIC },
274     { "la", USCRIPT_LATIN },
275     { "lah", USCRIPT_ARABIC },
276     { "lb", USCRIPT_LATIN },
277     { "lez", USCRIPT_CYRILLIC },
278     { "ln", USCRIPT_LATIN },
279     { "lo", USCRIPT_LAO },
280     { "lt", USCRIPT_LATIN },
281     { "lv", USCRIPT_LATIN },
282     { "mai", USCRIPT_DEVANAGARI },
283     { "mdf", USCRIPT_CYRILLIC },
284     { "mg", USCRIPT_LATIN },
285     { "mh", USCRIPT_LATIN },
286     { "mi", USCRIPT_LATIN },
287     { "mk", USCRIPT_CYRILLIC },
288     { "ml", USCRIPT_MALAYALAM },
289     { "mn", USCRIPT_CYRILLIC },
290     { "mr", USCRIPT_DEVANAGARI },
291     { "ms", USCRIPT_LATIN },
292     { "mt", USCRIPT_LATIN },
293     { "my", USCRIPT_MYANMAR },
294     { "myv", USCRIPT_CYRILLIC },
295     { "na", USCRIPT_LATIN },
296     { "nb", USCRIPT_LATIN },
297     { "ne", USCRIPT_DEVANAGARI },
298     { "niu", USCRIPT_LATIN },
299     { "nl", USCRIPT_LATIN },
300     { "nn", USCRIPT_LATIN },
301     { "nr", USCRIPT_LATIN },
302     { "nso", USCRIPT_LATIN },
303     { "ny", USCRIPT_LATIN },
304     { "oc", USCRIPT_LATIN },
305     { "om", USCRIPT_LATIN },
306     { "or", USCRIPT_ORIYA },
307     { "os", USCRIPT_CYRILLIC },
308     { "pa", USCRIPT_GURMUKHI },
309     { "pag", USCRIPT_LATIN },
310     { "pap", USCRIPT_LATIN },
311     { "pau", USCRIPT_LATIN },
312     { "pl", USCRIPT_LATIN },
313     { "pon", USCRIPT_LATIN },
314     { "ps", USCRIPT_ARABIC },
315     { "pt", USCRIPT_LATIN },
316     { "qu", USCRIPT_LATIN },
317     { "rm", USCRIPT_LATIN },
318     { "rn", USCRIPT_LATIN },
319     { "ro", USCRIPT_LATIN },
320     { "ru", USCRIPT_CYRILLIC },
321     { "rw", USCRIPT_LATIN },
322     { "sa", USCRIPT_DEVANAGARI },
323     { "sah", USCRIPT_CYRILLIC },
324     { "sat", USCRIPT_LATIN },
325     { "sd", USCRIPT_ARABIC },
326     { "se", USCRIPT_LATIN },
327     { "sg", USCRIPT_LATIN },
328     { "si", USCRIPT_SINHALA },
329     { "sid", USCRIPT_LATIN },
330     { "sk", USCRIPT_LATIN },
331     { "sl", USCRIPT_LATIN },
332     { "sm", USCRIPT_LATIN },
333     { "so", USCRIPT_LATIN },
334     { "sq", USCRIPT_LATIN },
335     { "sr", USCRIPT_CYRILLIC },
336     { "ss", USCRIPT_LATIN },
337     { "st", USCRIPT_LATIN },
338     { "su", USCRIPT_LATIN },
339     { "sv", USCRIPT_LATIN },
340     { "sw", USCRIPT_LATIN },
341     { "ta", USCRIPT_TAMIL },
342     { "te", USCRIPT_TELUGU },
343     { "tet", USCRIPT_LATIN },
344     { "tg", USCRIPT_CYRILLIC },
345     { "th", USCRIPT_THAI },
346     { "ti", USCRIPT_ETHIOPIC },
347     { "tig", USCRIPT_ETHIOPIC },
348     { "tk", USCRIPT_LATIN },
349     { "tkl", USCRIPT_LATIN },
350     { "tl", USCRIPT_LATIN },
351     { "tn", USCRIPT_LATIN },
352     { "to", USCRIPT_LATIN },
353     { "tpi", USCRIPT_LATIN },
354     { "tr", USCRIPT_LATIN },
355     { "trv", USCRIPT_LATIN },
356     { "ts", USCRIPT_LATIN },
357     { "tt", USCRIPT_CYRILLIC },
358     { "tvl", USCRIPT_LATIN },
359     { "tw", USCRIPT_LATIN },
360     { "ty", USCRIPT_LATIN },
361     { "tyv", USCRIPT_CYRILLIC },
362     { "udm", USCRIPT_CYRILLIC },
363     { "ug", USCRIPT_ARABIC },
364     { "uk", USCRIPT_CYRILLIC },
365     { "und", USCRIPT_LATIN },
366     { "ur", USCRIPT_ARABIC },
367     { "uz", USCRIPT_CYRILLIC },
368     { "ve", USCRIPT_LATIN },
369     { "vi", USCRIPT_LATIN },
370     { "wal", USCRIPT_ETHIOPIC },
371     { "war", USCRIPT_LATIN },
372     { "wo", USCRIPT_LATIN },
373     { "xh", USCRIPT_LATIN },
374     { "yap", USCRIPT_LATIN },
375     { "yo", USCRIPT_LATIN },
376     { "za", USCRIPT_LATIN },
377     { "zh", USCRIPT_HAN },
378     { "zh_hk", USCRIPT_TRADITIONAL_HAN },
379     { "zh_tw", USCRIPT_TRADITIONAL_HAN },
380     { "zu", USCRIPT_LATIN }
381 };
382
383 struct LocaleScriptMapHashTraits : public HashTraits<String> {
384     static const int minimumTableSize = WTF::HashTableCapacityForSize<WTF_ARRAY_LENGTH(localeScriptList)>::value;
385 };
386
387 UScriptCode localeToScriptCodeForFontSelection(const String& locale)
388 {
389     static const auto localeScriptMap = makeNeverDestroyed([] {
390         HashMap<String, UScriptCode, ASCIICaseInsensitiveHash, LocaleScriptMapHashTraits> map;
391         for (auto& localeAndScript : localeScriptList)
392             map.add(ASCIILiteral(localeAndScript.locale), localeAndScript.script);
393         return map;
394     }());
395
396     String canonicalLocale = locale;
397     canonicalLocale.replace('-', '_');
398     while (!canonicalLocale.isEmpty()) {
399         auto it = localeScriptMap.get().find(canonicalLocale);
400         if (it != localeScriptMap.get().end())
401             return it->value;
402         auto underscorePosition = canonicalLocale.reverseFind('_');
403         if (underscorePosition == notFound)
404             break;
405         UScriptCode code = scriptNameToCode(canonicalLocale.substring(underscorePosition + 1));
406         if (code != USCRIPT_INVALID_CODE && code != USCRIPT_UNKNOWN)
407             return code;
408         canonicalLocale = canonicalLocale.substring(0, underscorePosition);
409     }
410     return USCRIPT_COMMON;
411 }
412
413 } // namespace WebCore