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