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"
246c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka
25b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonaka#include "LocaleListCache.h"
266c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka#include "MinikinInternal.h"
27676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka#include "StringPiece.h"
28198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
2914e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin {
30198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
31676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t FIVE_BITS = 0x1f;
32198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
33b47e9b21077d2a0847a64fa713aa9892196b5d2aSeigo Nonakauint32_t registerLocaleList(const std::string& locales) {
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    }
456c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka    return (bufLen == subtagLen || buf[subtagLen] == '\0' || buf[subtagLen] == '-' ||
466c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka            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,
576c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka                                     uint8_t threeLetterBase) {
58676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (in.length() == 2) {
5922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return 0x7c00u |  // 0x1fu << 10
606c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka               (uint16_t)(in[0] - twoLetterBase) << 5 | (uint16_t)(in[1] - twoLetterBase);
6122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    } else {
62676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        return ((uint16_t)(in[0] - threeLetterBase) << 10) |
636c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka               (uint16_t)(in[1] - threeLetterBase) << 5 | (uint16_t)(in[2] - threeLetterBase);
6422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
6522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
6622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
6722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic size_t unpackLanguageOrRegion(uint16_t in, char* out, uint8_t twoLetterBase,
686c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka                                     uint8_t threeLetterBase) {
69676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint8_t first = (in >> 10) & FIVE_BITS;
70676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint8_t second = (in >> 5) & FIVE_BITS;
71676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint8_t third = in & FIVE_BITS;
7222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
7322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (first == 0x1f) {
7422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[0] = second + twoLetterBase;
7522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[1] = third + twoLetterBase;
7622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return 2;
7722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    } else {
7822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[0] = first + threeLetterBase;
7922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[1] = second + threeLetterBase;
8022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        out[2] = third + threeLetterBase;
8122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return 3;
8222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
8322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
8422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
85676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packLanguage(const StringPiece& in) {
86676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return packLanguageOrRegion(in, 'a', 'a');
87676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
88676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
89676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic size_t unpackLanguage(uint16_t in, char* out) {
90676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return unpackLanguageOrRegion(in, out, 'a', 'a');
91676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
92676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
93676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t packScript(char c1, char c2, char c3, char c4) {
94676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char FIRST_LETTER_BASE = 'A';
95676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char REST_LETTER_BASE = 'a';
96676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return ((uint32_t)(c1 - FIRST_LETTER_BASE) << 15) | (uint32_t)(c2 - REST_LETTER_BASE) << 10 |
976c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka           ((uint32_t)(c3 - REST_LETTER_BASE) << 5) | (uint32_t)(c4 - REST_LETTER_BASE);
98676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
99676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
100676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t packScript(uint32_t script) {
101676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return packScript(script >> 24, (script >> 16) & 0xff, (script >> 8) & 0xff, script & 0xff);
102676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
103676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
104676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t unpackScript(uint32_t packedScript) {
105676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char FIRST_LETTER_BASE = 'A';
106676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    constexpr char REST_LETTER_BASE = 'a';
107676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t first = (packedScript >> 15) + FIRST_LETTER_BASE;
108676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t second = ((packedScript >> 10) & FIVE_BITS) + REST_LETTER_BASE;
109676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t third = ((packedScript >> 5) & FIVE_BITS) + REST_LETTER_BASE;
110676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    const uint32_t fourth = (packedScript & FIVE_BITS) + REST_LETTER_BASE;
111676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
112676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return first << 24 | second << 16 | third << 8 | fourth;
113676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
114676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
115676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packRegion(const StringPiece& in) {
116676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return packLanguageOrRegion(in, 'A', '0');
117676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
118676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
119676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic size_t unpackRegion(uint16_t in, char* out) {
120676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return unpackLanguageOrRegion(in, out, 'A', '0');
12122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
12222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
12322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isLowercase(char c) {
12422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return 'a' <= c && c <= 'z';
12522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
12622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
12722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isUppercase(char c) {
12822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return 'A' <= c && c <= 'Z';
12922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
13022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
13122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isDigit(char c) {
13222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return '0' <= c && c <= '9';
13322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
13422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
13522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if the buffer is valid for language code.
136676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidLanguageCode(const StringPiece& buffer) {
137676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (buffer.length() != 2 && buffer.length() != 3) return false;
13822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (!isLowercase(buffer[0])) return false;
13922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (!isLowercase(buffer[1])) return false;
140676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (buffer.length() == 3 && !isLowercase(buffer[2])) return false;
14122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    return true;
14222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
14322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
14422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if buffer is valid for script code. The length of buffer must be 4.
145676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidScriptCode(const StringPiece& buffer) {
146676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return buffer.size() == 4 && isUppercase(buffer[0]) && isLowercase(buffer[1]) &&
1476c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka           isLowercase(buffer[2]) && isLowercase(buffer[3]);
14822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
14922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
15022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if the buffer is valid for region code.
151676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidRegionCode(const StringPiece& buffer) {
152676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return (buffer.size() == 2 && isUppercase(buffer[0]) && isUppercase(buffer[1])) ||
1536c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka           (buffer.size() == 3 && isDigit(buffer[0]) && isDigit(buffer[1]) && isDigit(buffer[2]));
15422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
15522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
156198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka// Parse BCP 47 language identifier into internal structure
1571d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocale::Locale(const StringPiece& input) : Locale() {
158676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    SplitIterator it(input, '-');
159676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
160676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    StringPiece language = it.next();
161676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (isValidLanguageCode(language)) {
162676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mLanguage = packLanguage(language);
163198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    } else {
164198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        // We don't understand anything other than two-letter or three-letter
165198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        // language codes, so we skip parsing the rest of the string.
166198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        return;
167198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
168198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
169676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (!it.hasNext()) {
17022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        return;  // Language code only.
17122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
172676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    StringPiece token = it.next();
17322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
174676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (isValidScriptCode(token)) {
175676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mScript = packScript(token[0], token[1], token[2], token[3]);
176676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mSubScriptBits = scriptToSubScriptBits(mScript);
17722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
178676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (!it.hasNext()) {
179676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            goto finalize;  // No variant, emoji subtag and region code.
180198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka        }
181676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        token = it.next();
182676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    }
18322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
184676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (isValidRegionCode(token)) {
185676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mRegion = packRegion(token);
18622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
187676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (!it.hasNext()) {
188676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            goto finalize;  // No variant or emoji subtag.
189676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        }
190676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        token = it.next();
191198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
192e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui
193676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (language == "de") {  // We are only interested in German variants.
194676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (token == "1901") {
195676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            mVariant = Variant::GERMAN_1901_ORTHOGRAPHY;
196676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        } else if (token == "1996") {
197676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            mVariant = Variant::GERMAN_1996_ORTHOGRAPHY;
198676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        }
199676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
200676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        if (mVariant != Variant::NO_VARIANT) {
201676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            if (!it.hasNext()) {
202676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                goto finalize;  // No emoji subtag.
203676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            }
204676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
205676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            token = it.next();
20622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        }
207e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
20822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
209676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    mEmojiStyle = resolveEmojiStyle(input.data(), input.length());
210676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka
211676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakafinalize:
2127fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    if (mEmojiStyle == EmojiStyle::EMPTY) {
213676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        mEmojiStyle = scriptToEmojiStyle(mScript);
214676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    }
21522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka}
21622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka
21722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// static
2187fbdd83e92a76c955c67a1c761088b36daf7158cSeigo NonakaEmojiStyle Locale::resolveEmojiStyle(const char* buf, size_t length) {
21922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    // First, lookup emoji subtag.
220e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    // 10 is the length of "-u-em-text", which is the shortest emoji subtag,
221e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    // unnecessary comparison can be avoided if total length is smaller than 10.
222e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    const size_t kMinSubtagLength = 10;
22322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    if (length >= kMinSubtagLength) {
22422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        static const char kPrefix[] = "-u-em-";
2256c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka        const char* pos = std::search(buf, buf + length, kPrefix, kPrefix + strlen(kPrefix));
22622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        if (pos != buf + length) {  // found
22722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            pos += strlen(kPrefix);
22822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            const size_t remainingLength = length - (pos - buf);
2296c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka            if (isEmojiSubtag(pos, remainingLength, "emoji", 5)) {
2307fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka                return EmojiStyle::EMOJI;
2316c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka            } else if (isEmojiSubtag(pos, remainingLength, "text", 4)) {
2327fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka                return EmojiStyle::TEXT;
2336c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka            } else if (isEmojiSubtag(pos, remainingLength, "default", 7)) {
2347fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka                return EmojiStyle::DEFAULT;
23522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka            }
23622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        }
237e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
2387fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    return EmojiStyle::EMPTY;
239676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka}
240e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui
2417fbdd83e92a76c955c67a1c761088b36daf7158cSeigo NonakaEmojiStyle Locale::scriptToEmojiStyle(uint32_t script) {
24222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    // If no emoji subtag was provided, resolve the emoji style from script code.
243676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (script == packScript('Z', 's', 'y', 'e')) {
2447fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka        return EmojiStyle::EMOJI;
245676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    } else if (script == packScript('Z', 's', 'y', 'm')) {
2467fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka        return EmojiStyle::TEXT;
247e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui    }
2487fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    return EmojiStyle::EMPTY;
249198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
250198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
2516c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka// static
2521d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakauint8_t Locale::scriptToSubScriptBits(uint32_t script) {
253198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    uint8_t subScriptBits = 0u;
254198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    switch (script) {
255676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('B', 'o', 'p', 'o'):
256533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            subScriptBits = kBopomofoFlag;
257533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            break;
258676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 'g'):
259198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHangulFlag;
260198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
261676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 'b'):
262533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            // Bopomofo is almost exclusively used in Taiwan.
263533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            subScriptBits = kHanFlag | kBopomofoFlag;
264533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka            break;
265676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 'i'):
266198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag;
267198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
268676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 's'):
269198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kSimplifiedChineseFlag;
270198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
271676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'a', 'n', 't'):
272198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kTraditionalChineseFlag;
273198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
274676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'i', 'r', 'a'):
275198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHiraganaFlag;
276198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
277676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('H', 'r', 'k', 't'):
278198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kKatakanaFlag | kHiraganaFlag;
279198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
280676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('J', 'p', 'a', 'n'):
281198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag;
282198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
283676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('K', 'a', 'n', 'a'):
284198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kKatakanaFlag;
285198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
286676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        case packScript('K', 'o', 'r', 'e'):
287198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            subScriptBits = kHanFlag | kHangulFlag;
288198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka            break;
289198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
290198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    return subScriptBits;
291198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
292198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
2931d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakastd::string Locale::getString() const {
294676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    char buf[24];
2958fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    size_t i;
2968fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if (mLanguage == NO_LANGUAGE) {
2978fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        buf[0] = 'u';
2988fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        buf[1] = 'n';
2998fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        buf[2] = 'd';
3008fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        i = 3;
3018fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    } else {
3028fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        i = unpackLanguage(mLanguage, buf);
3038fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3048fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if (mScript != NO_SCRIPT) {
305676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        uint32_t rawScript = unpackScript(mScript);
30622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        buf[i++] = '-';
307676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = (rawScript >> 24) & 0xFFu;
308676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = (rawScript >> 16) & 0xFFu;
309676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = (rawScript >> 8) & 0xFFu;
310676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = rawScript & 0xFFu;
31122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka    }
3128fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if (mRegion != NO_REGION) {
31322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka        buf[i++] = '-';
314676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        i += unpackRegion(mRegion, buf + i);
315676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    }
316676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (mVariant != Variant::NO_VARIANT) {
317676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = '-';
318676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = '1';
319676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        buf[i++] = '9';
320676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        switch (mVariant) {
321676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            case Variant::GERMAN_1901_ORTHOGRAPHY:
322676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '0';
323676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '1';
324676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                break;
325676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            case Variant::GERMAN_1996_ORTHOGRAPHY:
326676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '9';
327676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                buf[i++] = '6';
328676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka                break;
329676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka            default:
3301d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka                MINIKIN_ASSERT(false, "Must not reached.");
331676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka        }
332198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    }
333198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    return std::string(buf, i);
334198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
335198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
3361d461589869ee5b7102f96271b0ef0a776ab513cSeigo NonakaLocale Locale::getPartialLocale(SubtagBits bits) const {
3371d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    Locale subLocale;
3388fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::LANGUAGE) != SubtagBits::EMPTY) {
3398fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mLanguage = mLanguage;
3408fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    } else {
3418fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mLanguage = packLanguage("und");
3428fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3438fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::SCRIPT) != SubtagBits::EMPTY) {
3448fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mScript = mScript;
3458fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mSubScriptBits = mSubScriptBits;
3468fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3478fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::REGION) != SubtagBits::EMPTY) {
3488fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mRegion = mRegion;
3498fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3508fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::VARIANT) != SubtagBits::EMPTY) {
3518fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mVariant = mVariant;
3528fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3538fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    if ((bits & SubtagBits::EMOJI) != SubtagBits::EMPTY) {
3548fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka        subLocale.mEmojiStyle = mEmojiStyle;
3558fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    }
3568fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka    return subLocale;
3578fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka}
3588fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka
3591d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakabool Locale::isEqualScript(const Locale& other) const {
360198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka    return other.mScript == mScript;
361198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
362198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
363f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka// static
3641d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakabool Locale::supportsScript(uint8_t providedBits, uint8_t requestedBits) {
365f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    return requestedBits != 0 && (providedBits & requestedBits) == requestedBits;
3666f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka}
3676f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka
3681d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakabool Locale::supportsHbScript(hb_script_t script) const {
369676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    static_assert(unpackScript(packScript('J', 'p', 'a', 'n')) == HB_TAG('J', 'p', 'a', 'n'),
370198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka                  "The Minikin script and HarfBuzz hb_script_t have different encodings.");
371676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    uint32_t packedScript = packScript(script);
372676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    if (packedScript == mScript) return true;
373676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka    return supportsScript(mSubScriptBits, scriptToSubScriptBits(packedScript));
374198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
375198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
3761d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakaint Locale::calcScoreFor(const LocaleList& supported) const {
377d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    bool languageScriptMatch = false;
378d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    bool subtagMatch = false;
379d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    bool scriptMatch = false;
380d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang
381f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    for (size_t i = 0; i < supported.size(); ++i) {
3827fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka        if (mEmojiStyle != EmojiStyle::EMPTY && mEmojiStyle == supported[i].mEmojiStyle) {
383d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            subtagMatch = true;
384d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            if (mLanguage == supported[i].mLanguage) {
385d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang                return 4;
386d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            }
387d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        }
388f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        if (isEqualScript(supported[i]) ||
3896c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka            supportsScript(supported[i].mSubScriptBits, mSubScriptBits)) {
390d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            scriptMatch = true;
391f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka            if (mLanguage == supported[i].mLanguage) {
392d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang                languageScriptMatch = true;
393f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka            }
394f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        }
395f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    }
396f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
397f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    if (supportsScript(supported.getUnionOfSubScriptBits(), mSubScriptBits)) {
398d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        scriptMatch = true;
3991d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        if (mLanguage == supported[0].mLanguage && supported.isAllTheSameLocale()) {
400d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang            return 3;
401d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        }
402f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    }
403f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
404d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    if (languageScriptMatch) {
405d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        return 3;
406d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    } else if (subtagMatch) {
407d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        return 2;
408d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    } else if (scriptMatch) {
409d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang        return 1;
410d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang    }
411f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka    return 0;
412f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka}
413f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka
4141d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonakastatic hb_language_t buildHbLanguage(const Locale& locale) {
4156c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka    return locale.isSupported() ? hb_language_from_string(locale.getString().c_str(), -1)
4166c8722e217ff5238f0b849152d7936959a728103Seigo Nonaka                                : HB_LANGUAGE_INVALID;
4178fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka}
4188fbcbda6f9a2ee254ad8d22a5fe025e094fd6ff0Seigo Nonaka
4196c8722e217ff5238f0b849152d7936959a728103Seigo NonakaLocaleList::LocaleList(std::vector<Locale>&& locales) : mLocales(std::move(locales)) {
4201d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    mIsAllTheSameLocale = true;
4217fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    mUnionOfSubScriptBits = 0u;
4221d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka    mHbLangs.reserve(mLocales.size());
4237fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    mEmojiStyle = EmojiStyle::EMPTY;
4247fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    const auto firstLanguage = mLocales.empty() ? NO_LANGUAGE : mLocales[0].mLanguage;
4257fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka    for (const Locale& locale : mLocales) {
4261d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        mUnionOfSubScriptBits |= locale.mSubScriptBits;
4277fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka        if (mIsAllTheSameLocale && firstLanguage != locale.mLanguage) {
4281d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka            mIsAllTheSameLocale = false;
429f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka        }
4301d461589869ee5b7102f96271b0ef0a776ab513cSeigo Nonaka        mHbLangs.push_back(buildHbLanguage(locale));
4317fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka        if (mEmojiStyle == EmojiStyle::EMPTY) {
4327fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka            mEmojiStyle = locale.getEmojiStyle();
4337fbdd83e92a76c955c67a1c761088b36daf7158cSeigo Nonaka        }
4346f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka    }
435198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka}
436198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka
43714e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka}  // namespace minikin
438