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