Locale.cpp revision 676f8390ed8fa260f2f9685820b8d3dfbd08e8d3
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 17198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#define LOG_TAG "Minikin" 18198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 19198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include "FontLanguage.h" 20198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 21e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui#include <algorithm> 22676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka#include <cutils/log.h> 23198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include <hb.h> 24e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui#include <string.h> 25198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include <unicode/uloc.h> 26676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka#include "StringPiece.h" 27198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 2814e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonakanamespace minikin { 29198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 30676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t FIVE_BITS = 0x1f; 31198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 32e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui// Check if a language code supports emoji according to its subtag 33e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yiruistatic bool isEmojiSubtag(const char* buf, size_t bufLen, const char* subtag, size_t subtagLen) { 34e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui if (bufLen < subtagLen) { 35e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui return false; 36e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui } 37e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui if (strncmp(buf, subtag, subtagLen) != 0) { 38e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui return false; // no match between two strings 39e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui } 40e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui return (bufLen == subtagLen || buf[subtagLen] == '\0' || 41e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui buf[subtagLen] == '-' || buf[subtagLen] == '_'); 42e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui} 43e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui 4422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Pack the three letter code into 15 bits and stored to 16 bit integer. The highest bit is 0. 4522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// For the region code, the letters must be all digits in three letter case, so the number of 4622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// possible values are 10. For the language code, the letters must be all small alphabets, so the 4722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// number of possible values are 26. Thus, 5 bits are sufficient for each case and we can pack the 4822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// three letter language code or region code to 15 bits. 4922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// 5022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// In case of two letter code, use fullbit(0x1f) for the first letter instead. 51676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packLanguageOrRegion(const StringPiece& in, uint8_t twoLetterBase, 5222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka uint8_t threeLetterBase) { 53676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (in.length() == 2) { 5422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return 0x7c00u | // 0x1fu << 10 55676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka (uint16_t)(in[0] - twoLetterBase) << 5 | 56676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka (uint16_t)(in[1] - twoLetterBase); 5722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } else { 58676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return ((uint16_t)(in[0] - threeLetterBase) << 10) | 59676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka (uint16_t)(in[1] - threeLetterBase) << 5 | 60676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka (uint16_t)(in[2] - threeLetterBase); 6122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 6222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 6322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 6422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic size_t unpackLanguageOrRegion(uint16_t in, char* out, uint8_t twoLetterBase, 6522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka uint8_t threeLetterBase) { 66676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka uint8_t first = (in >> 10) & FIVE_BITS; 67676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka uint8_t second = (in >> 5) & FIVE_BITS; 68676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka uint8_t third = in & FIVE_BITS; 6922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 7022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (first == 0x1f) { 7122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka out[0] = second + twoLetterBase; 7222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka out[1] = third + twoLetterBase; 7322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return 2; 7422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } else { 7522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka out[0] = first + threeLetterBase; 7622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka out[1] = second + threeLetterBase; 7722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka out[2] = third + threeLetterBase; 7822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return 3; 7922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 8022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 8122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 82676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packLanguage(const StringPiece& in) { 83676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return packLanguageOrRegion(in, 'a', 'a'); 84676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 85676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 86676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic size_t unpackLanguage(uint16_t in, char* out) { 87676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return unpackLanguageOrRegion(in, out, 'a', 'a'); 88676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 89676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 90676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t packScript(char c1, char c2, char c3, char c4) { 91676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka constexpr char FIRST_LETTER_BASE = 'A'; 92676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka constexpr char REST_LETTER_BASE = 'a'; 93676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return ((uint32_t)(c1 - FIRST_LETTER_BASE) << 15) | (uint32_t)(c2 - REST_LETTER_BASE) << 10 | 94676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka ((uint32_t)(c3 - REST_LETTER_BASE) << 5) | (uint32_t)(c4 - REST_LETTER_BASE); 95676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 96676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 97676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t packScript(uint32_t script) { 98676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return packScript(script >> 24, (script >> 16) & 0xff, (script >> 8) & 0xff, script & 0xff); 99676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 100676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 101676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakaconstexpr uint32_t unpackScript(uint32_t packedScript) { 102676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka constexpr char FIRST_LETTER_BASE = 'A'; 103676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka constexpr char REST_LETTER_BASE = 'a'; 104676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka const uint32_t first = (packedScript >> 15) + FIRST_LETTER_BASE; 105676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka const uint32_t second = ((packedScript >> 10) & FIVE_BITS) + REST_LETTER_BASE; 106676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka const uint32_t third = ((packedScript >> 5) & FIVE_BITS) + REST_LETTER_BASE; 107676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka const uint32_t fourth = (packedScript & FIVE_BITS) + REST_LETTER_BASE; 108676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 109676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return first << 24 | second << 16 | third << 8 | fourth; 110676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 111676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 112676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic uint16_t packRegion(const StringPiece& in) { 113676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return packLanguageOrRegion(in, 'A', '0'); 114676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 115676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 116676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic size_t unpackRegion(uint16_t in, char* out) { 117676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return unpackLanguageOrRegion(in, out, 'A', '0'); 11822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 11922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 12022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isLowercase(char c) { 12122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return 'a' <= c && c <= 'z'; 12222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 12322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 12422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isUppercase(char c) { 12522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return 'A' <= c && c <= 'Z'; 12622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 12722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 12822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonakastatic inline bool isDigit(char c) { 12922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return '0' <= c && c <= '9'; 13022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 13122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 13222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if the buffer is valid for language code. 133676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidLanguageCode(const StringPiece& buffer) { 134676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (buffer.length() != 2 && buffer.length() != 3) return false; 13522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (!isLowercase(buffer[0])) return false; 13622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (!isLowercase(buffer[1])) return false; 137676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (buffer.length() == 3 && !isLowercase(buffer[2])) return false; 13822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return true; 13922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 14022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 14122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if buffer is valid for script code. The length of buffer must be 4. 142676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidScriptCode(const StringPiece& buffer) { 143676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return buffer.size() == 4 && isUppercase(buffer[0]) && isLowercase(buffer[1]) && 144676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka isLowercase(buffer[2]) && isLowercase(buffer[3]); 14522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 14622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 14722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// Returns true if the buffer is valid for region code. 148676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakastatic inline bool isValidRegionCode(const StringPiece& buffer) { 149676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return (buffer.size() == 2 && isUppercase(buffer[0]) && isUppercase(buffer[1])) || 150676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka (buffer.size() == 3 && isDigit(buffer[0]) && isDigit(buffer[1]) && isDigit(buffer[2])); 15122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 15222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 153198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka// Parse BCP 47 language identifier into internal structure 154676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo NonakaFontLanguage::FontLanguage(const StringPiece& input) : FontLanguage() { 155676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka SplitIterator it(input, '-'); 156676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 157676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka StringPiece language = it.next(); 158676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (isValidLanguageCode(language)) { 159676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mLanguage = packLanguage(language); 160198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } else { 161198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka // We don't understand anything other than two-letter or three-letter 162198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka // language codes, so we skip parsing the rest of the string. 163198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return; 164198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 165198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 166676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (!it.hasNext()) { 16722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka mHbLanguage = hb_language_from_string(getString().c_str(), -1); 16822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return; // Language code only. 16922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 170676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka StringPiece token = it.next(); 17122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 172676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (isValidScriptCode(token)) { 173676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mScript = packScript(token[0], token[1], token[2], token[3]); 174676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mSubScriptBits = scriptToSubScriptBits(mScript); 17522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 176676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (!it.hasNext()) { 177676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka goto finalize; // No variant, emoji subtag and region code. 178198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 179676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka token = it.next(); 180676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 18122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 182676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (isValidRegionCode(token)) { 183676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mRegion = packRegion(token); 18422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 185676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (!it.hasNext()) { 186676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka goto finalize; // No variant or emoji subtag. 187676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 188676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka token = it.next(); 189198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 190e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui 191676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (language == "de") { // We are only interested in German variants. 192676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (token == "1901") { 193676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mVariant = Variant::GERMAN_1901_ORTHOGRAPHY; 194676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } else if (token == "1996") { 195676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mVariant = Variant::GERMAN_1996_ORTHOGRAPHY; 196676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 197676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 198676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (mVariant != Variant::NO_VARIANT) { 199676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (!it.hasNext()) { 200676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka goto finalize; // No emoji subtag. 201676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 202676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 203676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka token = it.next(); 20422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 205e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui } 20622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 207676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mEmojiStyle = resolveEmojiStyle(input.data(), input.length()); 208676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka 209676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonakafinalize: 21022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka mHbLanguage = hb_language_from_string(getString().c_str(), -1); 211676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (mEmojiStyle == EMSTYLE_EMPTY) { 212676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka mEmojiStyle = scriptToEmojiStyle(mScript); 213676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 21422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka} 21522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka 21622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka// static 217676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo NonakaFontLanguage::EmojiStyle FontLanguage::resolveEmojiStyle(const char* buf, size_t length) { 21822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka // First, lookup emoji subtag. 219e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui // 10 is the length of "-u-em-text", which is the shortest emoji subtag, 220e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui // unnecessary comparison can be avoided if total length is smaller than 10. 221e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui const size_t kMinSubtagLength = 10; 22222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (length >= kMinSubtagLength) { 22322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka static const char kPrefix[] = "-u-em-"; 22422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka const char *pos = std::search(buf, buf + length, kPrefix, kPrefix + strlen(kPrefix)); 22522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (pos != buf + length) { // found 22622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka pos += strlen(kPrefix); 22722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka const size_t remainingLength = length - (pos - buf); 22822462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (isEmojiSubtag(pos, remainingLength, "emoji", 5)){ 22922462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return EMSTYLE_EMOJI; 23022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } else if (isEmojiSubtag(pos, remainingLength, "text", 4)){ 23122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return EMSTYLE_TEXT; 23222462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } else if (isEmojiSubtag(pos, remainingLength, "default", 7)){ 23322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return EMSTYLE_DEFAULT; 23422462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 23522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 236e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui } 237676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return EMSTYLE_EMPTY; 238676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka} 239e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui 240676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo NonakaFontLanguage::EmojiStyle FontLanguage::scriptToEmojiStyle(uint32_t script) { 24122462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka // If no emoji subtag was provided, resolve the emoji style from script code. 242676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (script == packScript('Z', 's', 'y', 'e')) { 24322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return EMSTYLE_EMOJI; 244676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } else if (script == packScript('Z', 's', 'y', 'm')) { 24522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return EMSTYLE_TEXT; 246e1d7f6168a0a485ecac75cfc9ae3bdc5143d0fb1yirui } 24722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka return EMSTYLE_EMPTY; 248198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 249198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 250198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka//static 251198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakauint8_t FontLanguage::scriptToSubScriptBits(uint32_t script) { 252198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka uint8_t subScriptBits = 0u; 253198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka switch (script) { 254676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('B', 'o', 'p', 'o'): 255533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka subScriptBits = kBopomofoFlag; 256533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka break; 257676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'a', 'n', 'g'): 258198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHangulFlag; 259198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 260676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'a', 'n', 'b'): 261533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka // Bopomofo is almost exclusively used in Taiwan. 262533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka subScriptBits = kHanFlag | kBopomofoFlag; 263533a01ea8438bb102b0dbc71f6c4ef356b260ed5Seigo Nonaka break; 264676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'a', 'n', 'i'): 265198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag; 266198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 267676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'a', 'n', 's'): 268198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kSimplifiedChineseFlag; 269198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 270676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'a', 'n', 't'): 271198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kTraditionalChineseFlag; 272198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 273676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'i', 'r', 'a'): 274198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHiraganaFlag; 275198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 276676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('H', 'r', 'k', 't'): 277198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kKatakanaFlag | kHiraganaFlag; 278198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 279676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('J', 'p', 'a', 'n'): 280198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag; 281198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 282676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('K', 'a', 'n', 'a'): 283198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kKatakanaFlag; 284198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 285676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case packScript('K', 'o', 'r', 'e'): 286198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kHangulFlag; 287198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 288198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 289198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return subScriptBits; 290198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 291198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 292198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakastd::string FontLanguage::getString() const { 29322462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (isUnsupported()) { 294198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return "und"; 295198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 296676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka char buf[24]; 297676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka size_t i = unpackLanguage(mLanguage, buf); 298676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (mScript != INVALID_SCRIPT) { 299676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka uint32_t rawScript = unpackScript(mScript); 30022462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka buf[i++] = '-'; 301676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = (rawScript >> 24) & 0xFFu; 302676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = (rawScript >> 16) & 0xFFu; 303676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = (rawScript >> 8) & 0xFFu; 304676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = rawScript & 0xFFu; 30522462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka } 30622462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka if (mRegion != INVALID_CODE) { 30722462be7358f1facbe0c0074f8e58a41c2314b6eSeigo Nonaka buf[i++] = '-'; 308676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka i += unpackRegion(mRegion, buf + i); 309676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 310676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (mVariant != Variant::NO_VARIANT) { 311676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '-'; 312676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '1'; 313676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '9'; 314676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka switch (mVariant) { 315676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case Variant::GERMAN_1901_ORTHOGRAPHY: 316676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '0'; 317676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '1'; 318676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka break; 319676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka case Variant::GERMAN_1996_ORTHOGRAPHY: 320676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '9'; 321676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka buf[i++] = '6'; 322676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka break; 323676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka default: 324676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka LOG_ALWAYS_FATAL("Must not reached."); 325676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka } 326198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 327198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return std::string(buf, i); 328198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 329198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 3306f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakabool FontLanguage::isEqualScript(const FontLanguage& other) const { 331198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return other.mScript == mScript; 332198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 333198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 334f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka// static 335f3afe92def0fff022889fd036d68451223aac146Seigo Nonakabool FontLanguage::supportsScript(uint8_t providedBits, uint8_t requestedBits) { 336f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka return requestedBits != 0 && (providedBits & requestedBits) == requestedBits; 3376f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka} 3386f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 339198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakabool FontLanguage::supportsHbScript(hb_script_t script) const { 340676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka static_assert(unpackScript(packScript('J', 'p', 'a', 'n')) == HB_TAG('J', 'p', 'a', 'n'), 341198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka "The Minikin script and HarfBuzz hb_script_t have different encodings."); 342676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka uint32_t packedScript = packScript(script); 343676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka if (packedScript == mScript) return true; 344676f8390ed8fa260f2f9685820b8d3dfbd08e8d3Seigo Nonaka return supportsScript(mSubScriptBits, scriptToSubScriptBits(packedScript)); 345198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 346198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 347f3afe92def0fff022889fd036d68451223aac146Seigo Nonakaint FontLanguage::calcScoreFor(const FontLanguages& supported) const { 348d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang bool languageScriptMatch = false; 349d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang bool subtagMatch = false; 350d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang bool scriptMatch = false; 351d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang 352f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka for (size_t i = 0; i < supported.size(); ++i) { 353d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang if (mEmojiStyle != EMSTYLE_EMPTY && 354d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang mEmojiStyle == supported[i].mEmojiStyle) { 355d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang subtagMatch = true; 356d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang if (mLanguage == supported[i].mLanguage) { 357d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang return 4; 358d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang } 359d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang } 360f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka if (isEqualScript(supported[i]) || 361f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka supportsScript(supported[i].mSubScriptBits, mSubScriptBits)) { 362d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang scriptMatch = true; 363f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka if (mLanguage == supported[i].mLanguage) { 364d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang languageScriptMatch = true; 365f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka } 366f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka } 367f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka } 368f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka 369f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka if (supportsScript(supported.getUnionOfSubScriptBits(), mSubScriptBits)) { 370d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang scriptMatch = true; 371d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang if (mLanguage == supported[0].mLanguage && supported.isAllTheSameLanguage()) { 372d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang return 3; 373d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang } 374f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka } 375f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka 376d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang if (languageScriptMatch) { 377d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang return 3; 378d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang } else if (subtagMatch) { 379d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang return 2; 380d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang } else if (scriptMatch) { 381d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang return 1; 382d478da324d3b98e736b6c42415c02d506cfb653fYirui Huang } 383f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka return 0; 384f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka} 385f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka 386f3afe92def0fff022889fd036d68451223aac146Seigo NonakaFontLanguages::FontLanguages(std::vector<FontLanguage>&& languages) 387f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka : mLanguages(std::move(languages)) { 388f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka if (mLanguages.empty()) { 389f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka return; 390f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka } 391f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka 392f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka const FontLanguage& lang = mLanguages[0]; 393f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka 394f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka mIsAllTheSameLanguage = true; 395f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka mUnionOfSubScriptBits = lang.mSubScriptBits; 396f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka for (size_t i = 1; i < mLanguages.size(); ++i) { 397f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka mUnionOfSubScriptBits |= mLanguages[i].mSubScriptBits; 398f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka if (mIsAllTheSameLanguage && lang.mLanguage != mLanguages[i].mLanguage) { 399f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka mIsAllTheSameLanguage = false; 400f3afe92def0fff022889fd036d68451223aac146Seigo Nonaka } 4016f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 402198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 403198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 40414e2d136aaef271ba131f917cf5f27baa31ae5adSeigo Nonaka} // namespace minikin 405