Locale.cpp revision 6f9966ea7c1910fd780cf7779cc59701c9b98a2b
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 21198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include <hb.h> 22198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#include <unicode/uloc.h> 23198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 24198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakanamespace android { 25198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 26198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#define SCRIPT_TAG(c1, c2, c3, c4) \ 27198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka (((uint32_t)(c1)) << 24 | ((uint32_t)(c2)) << 16 | ((uint32_t)(c3)) << 8 | \ 28198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka ((uint32_t)(c4))) 29198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 30198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka// Parse BCP 47 language identifier into internal structure 31198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo NonakaFontLanguage::FontLanguage(const char* buf, size_t length) : FontLanguage() { 32198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka size_t i; 33198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka for (i = 0; i < length; i++) { 34198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka char c = buf[i]; 35198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (c == '-' || c == '_') break; 36198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 37198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (i == 2 || i == 3) { // only accept two or three letter language code. 38198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka mLanguage = buf[0] | (buf[1] << 8) | ((i == 3) ? (buf[2] << 16) : 0); 39198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } else { 40198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka // We don't understand anything other than two-letter or three-letter 41198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka // language codes, so we skip parsing the rest of the string. 42198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka mLanguage = 0ul; 43198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return; 44198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 45198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 46198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka size_t next; 47198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka for (i++; i < length; i = next + 1) { 48198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka for (next = i; next < length; next++) { 49198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka char c = buf[next]; 50198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (c == '-' || c == '_') break; 51198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 52198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (next - i == 4 && 'A' <= buf[i] && buf[i] <= 'Z') { 53198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka mScript = SCRIPT_TAG(buf[i], buf[i + 1], buf[i + 2], buf[i + 3]); 54198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 55198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 56198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 57198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka mSubScriptBits = scriptToSubScriptBits(mScript); 58198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 59198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 60198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka//static 61198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakauint8_t FontLanguage::scriptToSubScriptBits(uint32_t script) { 62198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka uint8_t subScriptBits = 0u; 63198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka switch (script) { 64198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('H', 'a', 'n', 'g'): 65198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHangulFlag; 66198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 67198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('H', 'a', 'n', 'i'): 68198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag; 69198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 70198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('H', 'a', 'n', 's'): 71198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kSimplifiedChineseFlag; 72198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 73198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('H', 'a', 'n', 't'): 74198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kTraditionalChineseFlag; 75198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 76198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('H', 'i', 'r', 'a'): 77198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHiraganaFlag; 78198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 79198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('H', 'r', 'k', 't'): 80198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kKatakanaFlag | kHiraganaFlag; 81198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 82198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('J', 'p', 'a', 'n'): 83198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag; 84198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 85198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('K', 'a', 'n', 'a'): 86198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kKatakanaFlag; 87198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 88198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka case SCRIPT_TAG('K', 'o', 'r', 'e'): 89198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kHanFlag | kHangulFlag; 90198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 91d3376522332e1e016e59fabb22c24025092c724dSeigo Nonaka case SCRIPT_TAG('Z', 's', 'y', 'e'): 92198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka subScriptBits = kEmojiFlag; 93198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka break; 94198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 95198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return subScriptBits; 96198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 97198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 98198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakastd::string FontLanguage::getString() const { 99198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (mLanguage == 0ul) { 100198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return "und"; 101198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 102198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka char buf[16]; 103198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka size_t i = 0; 104198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = mLanguage & 0xFF ; 105198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = (mLanguage >> 8) & 0xFF; 106198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka char third_letter = (mLanguage >> 16) & 0xFF; 107198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (third_letter != 0) buf[i++] = third_letter; 108198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (mScript != 0) { 109198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = '-'; 110198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = (mScript >> 24) & 0xFFu; 111198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = (mScript >> 16) & 0xFFu; 112198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = (mScript >> 8) & 0xFFu; 113198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka buf[i++] = mScript & 0xFFu; 114198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka } 115198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return std::string(buf, i); 116198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 117198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 1186f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakabool FontLanguage::isEqualScript(const FontLanguage& other) const { 119198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka return other.mScript == mScript; 120198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 121198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 1226f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakabool FontLanguage::supportsScript(uint8_t requestedBits) const { 1236f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return requestedBits != 0 && (mSubScriptBits & requestedBits) == requestedBits; 1246f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka} 1256f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka 126198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonakabool FontLanguage::supportsHbScript(hb_script_t script) const { 127198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka static_assert(SCRIPT_TAG('J', 'p', 'a', 'n') == HB_TAG('J', 'p', 'a', 'n'), 128198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka "The Minikin script and HarfBuzz hb_script_t have different encodings."); 129198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka if (script == mScript) return true; 1306f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return supportsScript(scriptToSubScriptBits(script)); 131198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 132198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 1336f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonakaint FontLanguage::getScoreFor(const FontLanguage other) const { 1346f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka if (isUnsupported() || other.isUnsupported()) { 1356f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return 0; 1366f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } else if (isEqualScript(other) || supportsScript(other.mSubScriptBits)) { 1376f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return mLanguage == other.mLanguage ? 2 : 1; 1386f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } else { 1396f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka return 0; 1406f9966ea7c1910fd780cf7779cc59701c9b98a2bSeigo Nonaka } 141198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} 142198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka 143198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka#undef SCRIPT_TAG 144198b46f1fea3f47ef8eb6317799c0d77aaec52f6Seigo Nonaka} // namespace android 145