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