Locale.cpp revision b47e9b21077d2a0847a64fa713aa9892196b5d2a
1198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka/*
2198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * Copyright (C) 2015 The Android Open Source Project
3198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka *
4198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * Licensed under the Apache License, Version 2.0 (the "License");
5198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * you may not use this file except in compliance with the License.
6198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * You may obtain a copy of the License at
7198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka *
8198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka *      http://www.apache.org/licenses/LICENSE-2.0
9198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka *
10198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * Unless required by applicable law or agreed to in writing, software
11198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * distributed under the License is distributed on an "AS IS" BASIS,
12198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * See the License for the specific language governing permissions and
14198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka * limitations under the License.
15198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka */
16198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
171d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka#include "Locale.h"
18198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
19e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui#include <algorithm>
201d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka
21198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include <hb.h>
221d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka
23b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka#include "minikin/LocaleList.h"
241d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka#include "MinikinInternal.h"
25b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka#include "LocaleListCache.h"
26676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka#include "StringPiece.h"
27198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
2814e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
29198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
30676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t FIVE_BITS = 0x1f;
31198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
32b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonakauint32_t registerLocaleList(const std::string& locales) {
33b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka    android::AutoMutex _l(gMinikinLock);
34b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka    return LocaleListCache::getId(locales);
35b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka}
36b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka
37e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui// Check if a language code supports emoji according to its subtag
38e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yiruistatic bool isEmojiSubtag(const char* buf, size_t bufLen, const char* subtag, size_t subtagLen) {
39e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    if (bufLen < subtagLen) {
40e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui        return false;
41e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
42e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    if (strncmp(buf, subtag, subtagLen) != 0) {
43e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui        return false;  // no match between two strings
44e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
45e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    return (bufLen == subtagLen || buf[subtagLen] == '\0' ||
46e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui            buf[subtagLen] == '-' || buf[subtagLen] == '_');
47e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui}
48e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui
4922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Pack the three letter code into 15 bits and stored to 16 bit integer. The highest bit is 0.
5022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// For the region code, the letters must be all digits in three letter case, so the number of
5122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// possible values are 10. For the language code, the letters must be all small alphabets, so the
5222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// number of possible values are 26. Thus, 5 bits are sufficient for each case and we can pack the
5322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// three letter language code or region code to 15 bits.
5422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka//
5522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// In case of two letter code, use fullbit(0x1f) for the first letter instead.
56676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packLanguageOrRegion(const StringPiece& in, uint8_t twoLetterBase,
5722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        uint8_t threeLetterBase) {
58676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (in.length() == 2) {
5922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return 0x7c00u |  // 0x1fu << 10
60676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                (uint16_t)(in[0] - twoLetterBase) << 5 |
61676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                (uint16_t)(in[1] - twoLetterBase);
6222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    } else {
63676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        return ((uint16_t)(in[0] - threeLetterBase) << 10) |
64676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                (uint16_t)(in[1] - threeLetterBase) << 5 |
65676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                (uint16_t)(in[2] - threeLetterBase);
6622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
6722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
6822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
6922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic size_t unpackLanguageOrRegion(uint16_t in, char* out, uint8_t twoLetterBase,
7022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        uint8_t threeLetterBase) {
71676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint8_t first = (in >> 10) & FIVE_BITS;
72676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint8_t second = (in >> 5) & FIVE_BITS;
73676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint8_t third = in & FIVE_BITS;
7422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
7522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (first == 0x1f) {
7622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[0] = second + twoLetterBase;
7722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[1] = third + twoLetterBase;
7822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return 2;
7922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    } else {
8022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[0] = first + threeLetterBase;
8122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[1] = second + threeLetterBase;
8222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[2] = third + threeLetterBase;
8322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return 3;
8422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
8522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
8622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
87676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packLanguage(const StringPiece& in) {
88676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return packLanguageOrRegion(in, 'a', 'a');
89676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
90676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
91676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic size_t unpackLanguage(uint16_t in, char* out) {
92676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return unpackLanguageOrRegion(in, out, 'a', 'a');
93676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
94676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
95676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t packScript(char c1, char c2, char c3, char c4) {
96676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char FIRST_LETTER_BASE = 'A';
97676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char REST_LETTER_BASE = 'a';
98676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return ((uint32_t)(c1 - FIRST_LETTER_BASE) << 15) | (uint32_t)(c2 - REST_LETTER_BASE) << 10 |
99676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            ((uint32_t)(c3 - REST_LETTER_BASE) << 5) | (uint32_t)(c4 - REST_LETTER_BASE);
100676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
101676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
102676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t packScript(uint32_t script) {
103676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return packScript(script >> 24, (script >> 16) & 0xff, (script >> 8) & 0xff, script & 0xff);
104676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
105676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
106676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t unpackScript(uint32_t packedScript) {
107676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char FIRST_LETTER_BASE = 'A';
108676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char REST_LETTER_BASE = 'a';
109676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t first = (packedScript >> 15) + FIRST_LETTER_BASE;
110676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t second = ((packedScript >> 10) & FIVE_BITS) + REST_LETTER_BASE;
111676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t third = ((packedScript >> 5) & FIVE_BITS) + REST_LETTER_BASE;
112676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t fourth = (packedScript & FIVE_BITS) + REST_LETTER_BASE;
113676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
114676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return first << 24 | second << 16 | third << 8 | fourth;
115676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
116676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
117676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packRegion(const StringPiece& in) {
118676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return packLanguageOrRegion(in, 'A', '0');
119676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
120676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
121676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic size_t unpackRegion(uint16_t in, char* out) {
122676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return unpackLanguageOrRegion(in, out, 'A', '0');
12322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
12422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
12522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isLowercase(char c) {
12622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return 'a' <= c && c <= 'z';
12722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
12822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
12922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isUppercase(char c) {
13022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return 'A' <= c && c <= 'Z';
13122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
13222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
13322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isDigit(char c) {
13422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return '0' <= c && c <= '9';
13522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
13622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
13722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if the buffer is valid for language code.
138676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidLanguageCode(const StringPiece& buffer) {
139676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (buffer.length() != 2 && buffer.length() != 3) return false;
14022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (!isLowercase(buffer[0])) return false;
14122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (!isLowercase(buffer[1])) return false;
142676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (buffer.length() == 3 && !isLowercase(buffer[2])) return false;
14322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return true;
14422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
14522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
14622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if buffer is valid for script code. The length of buffer must be 4.
147676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidScriptCode(const StringPiece& buffer) {
148676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return buffer.size() == 4 && isUppercase(buffer[0]) && isLowercase(buffer[1]) &&
149676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            isLowercase(buffer[2]) && isLowercase(buffer[3]);
15022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
15122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
15222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if the buffer is valid for region code.
153676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidRegionCode(const StringPiece& buffer) {
154676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return (buffer.size() == 2 && isUppercase(buffer[0]) && isUppercase(buffer[1])) ||
155676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            (buffer.size() == 3 && isDigit(buffer[0]) && isDigit(buffer[1]) && isDigit(buffer[2]));
15622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
15722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
158198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka// Parse BCP 47 language identifier into internal structure
1591d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocale::Locale(const StringPiece& input) : Locale() {
160676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    SplitIterator it(input, '-');
161676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
162676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    StringPiece language = it.next();
163676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (isValidLanguageCode(language)) {
164676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mLanguage = packLanguage(language);
165198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    } else {
166198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        // We don't understand anything other than two-letter or three-letter
167198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        // language codes, so we skip parsing the rest of the string.
168198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        return;
169198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
170198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
171676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (!it.hasNext()) {
17222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return;  // Language code only.
17322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
174676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    StringPiece token = it.next();
17522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
176676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (isValidScriptCode(token)) {
177676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mScript = packScript(token[0], token[1], token[2], token[3]);
178676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mSubScriptBits = scriptToSubScriptBits(mScript);
17922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
180676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (!it.hasNext()) {
181676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            goto finalize;  // No variant, emoji subtag and region code.
182198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        }
183676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        token = it.next();
184676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    }
18522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
186676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (isValidRegionCode(token)) {
187676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mRegion = packRegion(token);
18822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
189676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (!it.hasNext()) {
190676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            goto finalize;  // No variant or emoji subtag.
191676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        }
192676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        token = it.next();
193198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
194e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui
195676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (language == "de") {  // We are only interested in German variants.
196676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (token == "1901") {
197676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            mVariant = Variant::GERMAN_1901_ORTHOGRAPHY;
198676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        } else if (token == "1996") {
199676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            mVariant = Variant::GERMAN_1996_ORTHOGRAPHY;
200676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        }
201676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
202676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (mVariant != Variant::NO_VARIANT) {
203676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            if (!it.hasNext()) {
204676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                goto finalize;  // No emoji subtag.
205676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            }
206676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
207676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            token = it.next();
20822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        }
209e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
21022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
211676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    mEmojiStyle = resolveEmojiStyle(input.data(), input.length());
212676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
213676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakafinalize:
214676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (mEmojiStyle == EMSTYLE_EMPTY) {
215676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mEmojiStyle = scriptToEmojiStyle(mScript);
216676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    }
21722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
21822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
21922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// static
2201d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocale::EmojiStyle Locale::resolveEmojiStyle(const char* buf, size_t length) {
22122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    // First, lookup emoji subtag.
222e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    // 10 is the length of "-u-em-text", which is the shortest emoji subtag,
223e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    // unnecessary comparison can be avoided if total length is smaller than 10.
224e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    const size_t kMinSubtagLength = 10;
22522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (length >= kMinSubtagLength) {
22622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        static const char kPrefix[] = "-u-em-";
22722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        const char *pos = std::search(buf, buf + length, kPrefix, kPrefix + strlen(kPrefix));
22822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        if (pos != buf + length) {  // found
22922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            pos += strlen(kPrefix);
23022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            const size_t remainingLength = length - (pos - buf);
23122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            if (isEmojiSubtag(pos, remainingLength, "emoji", 5)){
23222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka                return EMSTYLE_EMOJI;
23322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            } else if (isEmojiSubtag(pos, remainingLength, "text", 4)){
23422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka                return EMSTYLE_TEXT;
23522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            } else if (isEmojiSubtag(pos, remainingLength, "default", 7)){
23622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka                return EMSTYLE_DEFAULT;
23722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            }
23822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        }
239e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
240676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return EMSTYLE_EMPTY;
241676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
242e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui
2431d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocale::EmojiStyle Locale::scriptToEmojiStyle(uint32_t script) {
24422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    // If no emoji subtag was provided, resolve the emoji style from script code.
245676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (script == packScript('Z', 's', 'y', 'e')) {
24622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return EMSTYLE_EMOJI;
247676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    } else if (script == packScript('Z', 's', 'y', 'm')) {
24822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return EMSTYLE_TEXT;
249e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
25022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return EMSTYLE_EMPTY;
251198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
252198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
253198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka//static
2541d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakauint8_t Locale::scriptToSubScriptBits(uint32_t script) {
255198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    uint8_t subScriptBits = 0u;
256198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    switch (script) {
257676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('B', 'o', 'p', 'o'):
258533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            subScriptBits = kBopomofoFlag;
259533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            break;
260676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 'g'):
261198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHangulFlag;
262198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
263676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 'b'):
264533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            // Bopomofo is almost exclusively used in Taiwan.
265533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            subScriptBits = kHanFlag | kBopomofoFlag;
266533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            break;
267676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 'i'):
268198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag;
269198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
270676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 's'):
271198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kSimplifiedChineseFlag;
272198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
273676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 't'):
274198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kTraditionalChineseFlag;
275198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
276676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'i', 'r', 'a'):
277198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHiraganaFlag;
278198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
279676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'r', 'k', 't'):
280198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kKatakanaFlag | kHiraganaFlag;
281198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
282676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('J', 'p', 'a', 'n'):
283198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag;
284198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
285676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('K', 'a', 'n', 'a'):
286198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kKatakanaFlag;
287198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
288676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('K', 'o', 'r', 'e'):
289198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kHangulFlag;
290198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
291198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
292198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    return subScriptBits;
293198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
294198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
2951d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakastd::string Locale::getString() const {
296676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    char buf[24];
2978fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    size_t i;
2988fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if (mLanguage == NO_LANGUAGE) {
2998fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        buf[0] = 'u';
3008fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        buf[1] = 'n';
3018fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        buf[2] = 'd';
3028fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        i = 3;
3038fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    } else {
3048fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        i = unpackLanguage(mLanguage, buf);
3058fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3068fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if (mScript != NO_SCRIPT) {
307676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        uint32_t rawScript = unpackScript(mScript);
30822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        buf[i++] = '-';
309676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = (rawScript >> 24) & 0xFFu;
310676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = (rawScript >> 16) & 0xFFu;
311676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = (rawScript >> 8) & 0xFFu;
312676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = rawScript & 0xFFu;
31322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
3148fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if (mRegion != NO_REGION) {
31522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        buf[i++] = '-';
316676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        i += unpackRegion(mRegion, buf + i);
317676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    }
318676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (mVariant != Variant::NO_VARIANT) {
319676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = '-';
320676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = '1';
321676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = '9';
322676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        switch (mVariant) {
323676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            case Variant::GERMAN_1901_ORTHOGRAPHY:
324676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '0';
325676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '1';
326676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                break;
327676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            case Variant::GERMAN_1996_ORTHOGRAPHY:
328676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '9';
329676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '6';
330676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                break;
331676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            default:
3321d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka                MINIKIN_ASSERT(false, "Must not reached.");
333676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        }
334198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
335198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    return std::string(buf, i);
336198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
337198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
3381d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocale Locale::getPartialLocale(SubtagBits bits) const {
3391d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    Locale subLocale;
3408fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::LANGUAGE) != SubtagBits::EMPTY) {
3418fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mLanguage = mLanguage;
3428fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    } else {
3438fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mLanguage = packLanguage("und");
3448fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3458fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::SCRIPT) != SubtagBits::EMPTY) {
3468fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mScript = mScript;
3478fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mSubScriptBits = mSubScriptBits;
3488fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3498fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::REGION) != SubtagBits::EMPTY) {
3508fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mRegion = mRegion;
3518fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3528fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::VARIANT) != SubtagBits::EMPTY) {
3538fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mVariant = mVariant;
3548fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3558fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::EMOJI) != SubtagBits::EMPTY) {
3568fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mEmojiStyle = mEmojiStyle;
3578fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3588fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    return subLocale;
3598fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka}
3608fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka
3611d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakabool Locale::isEqualScript(const Locale& other) const {
362198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    return other.mScript == mScript;
363198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
364198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
365f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka// static
3661d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakabool Locale::supportsScript(uint8_t providedBits, uint8_t requestedBits) {
367f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    return requestedBits != 0 && (providedBits & requestedBits) == requestedBits;
3686f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka}
3696f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka
3701d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakabool Locale::supportsHbScript(hb_script_t script) const {
371676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    static_assert(unpackScript(packScript('J', 'p', 'a', 'n')) == HB_TAG('J', 'p', 'a', 'n'),
372198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka                  "The Minikin script and HarfBuzz hb_script_t have different encodings.");
373676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint32_t packedScript = packScript(script);
374676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (packedScript == mScript) return true;
375676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return supportsScript(mSubScriptBits, scriptToSubScriptBits(packedScript));
376198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
377198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
3781d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakaint Locale::calcScoreFor(const LocaleList& supported) const {
379d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    bool languageScriptMatch = false;
380d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    bool subtagMatch = false;
381d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    bool scriptMatch = false;
382d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang
383f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    for (size_t i = 0; i < supported.size(); ++i) {
384d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        if (mEmojiStyle != EMSTYLE_EMPTY &&
385d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang               mEmojiStyle == supported[i].mEmojiStyle) {
386d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            subtagMatch = true;
387d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            if (mLanguage == supported[i].mLanguage) {
388d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang                return 4;
389d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            }
390d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        }
391f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        if (isEqualScript(supported[i]) ||
392f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka                supportsScript(supported[i].mSubScriptBits, mSubScriptBits)) {
393d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            scriptMatch = true;
394f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka            if (mLanguage == supported[i].mLanguage) {
395d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang                languageScriptMatch = true;
396f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka            }
397f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        }
398f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    }
399f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
400f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    if (supportsScript(supported.getUnionOfSubScriptBits(), mSubScriptBits)) {
401d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        scriptMatch = true;
4021d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        if (mLanguage == supported[0].mLanguage && supported.isAllTheSameLocale()) {
403d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            return 3;
404d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        }
405f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    }
406f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
407d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    if (languageScriptMatch) {
408d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        return 3;
409d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    } else if (subtagMatch) {
410d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        return 2;
411d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    } else if (scriptMatch) {
412d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        return 1;
413d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    }
414f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    return 0;
415f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka}
416f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
4171d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakastatic hb_language_t buildHbLanguage(const Locale& locale) {
4181d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    return locale.isSupported() ?
4191d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka            hb_language_from_string(locale.getString().c_str(), -1) : HB_LANGUAGE_INVALID;
4208fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka}
4218fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka
4221d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocaleList::LocaleList(std::vector<Locale>&& locales)
4231d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    : mLocales(std::move(locales)) {
4241d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    if (mLocales.empty()) {
425f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        return;
426f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    }
427f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
4281d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    const Locale& firstLocale = mLocales[0];
4291d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka
4301d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    mIsAllTheSameLocale = true;
4311d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    mUnionOfSubScriptBits = firstLocale.mSubScriptBits;
4321d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    mHbLangs.reserve(mLocales.size());
4331d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    mHbLangs.push_back(buildHbLanguage(firstLocale));
4341d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    for (size_t i = 1; i < mLocales.size(); ++i) {
4351d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        const Locale& locale = mLocales[i];
4361d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        mUnionOfSubScriptBits |= locale.mSubScriptBits;
4371d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        if (mIsAllTheSameLocale && firstLocale.mLanguage != locale.mLanguage) {
4381d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka            mIsAllTheSameLocale = false;
439f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        }
4401d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        mHbLangs.push_back(buildHbLanguage(locale));
4416f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka    }
4428fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka
4438fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka
444198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
445198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
44614e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
447