FontLanguage.cpp revision 5e995fb850c2b32631914c3815dfb421855fba9b
1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "Minikin" 18 19#include "FontLanguage.h" 20 21#include <hb.h> 22#include <unicode/uloc.h> 23 24namespace android { 25 26#define SCRIPT_TAG(c1, c2, c3, c4) \ 27 ((uint32_t)(c1)) << 24 | ((uint32_t)(c2)) << 16 | ((uint32_t)(c3)) << 8 | ((uint32_t)(c4)) 28 29// Parse BCP 47 language identifier into internal structure 30FontLanguage::FontLanguage(const char* buf, size_t length) : FontLanguage() { 31 size_t i; 32 for (i = 0; i < length; i++) { 33 char c = buf[i]; 34 if (c == '-' || c == '_') break; 35 } 36 if (i == 2 || i == 3) { // only accept two or three letter language code. 37 mLanguage = buf[0] | (buf[1] << 8) | ((i == 3) ? (buf[2] << 16) : 0); 38 } else { 39 // We don't understand anything other than two-letter or three-letter 40 // language codes, so we skip parsing the rest of the string. 41 mLanguage = 0ul; 42 return; 43 } 44 45 size_t next; 46 for (i++; i < length; i = next + 1) { 47 for (next = i; next < length; next++) { 48 char c = buf[next]; 49 if (c == '-' || c == '_') break; 50 } 51 if (next - i == 4 && 'A' <= buf[i] && buf[i] <= 'Z') { 52 mScript = SCRIPT_TAG(buf[i], buf[i + 1], buf[i + 2], buf[i + 3]); 53 } 54 } 55 56 mSubScriptBits = scriptToSubScriptBits(mScript); 57} 58 59//static 60uint8_t FontLanguage::scriptToSubScriptBits(uint32_t script) { 61 uint8_t subScriptBits = 0u; 62 switch (script) { 63 case SCRIPT_TAG('H', 'a', 'n', 'g'): 64 subScriptBits = kHangulFlag; 65 break; 66 case SCRIPT_TAG('H', 'a', 'n', 'i'): 67 subScriptBits = kHanFlag; 68 break; 69 case SCRIPT_TAG('H', 'a', 'n', 's'): 70 subScriptBits = kHanFlag | kSimplifiedChineseFlag; 71 break; 72 case SCRIPT_TAG('H', 'a', 'n', 't'): 73 subScriptBits = kHanFlag | kTraditionalChineseFlag; 74 break; 75 case SCRIPT_TAG('H', 'i', 'r', 'a'): 76 subScriptBits = kHiraganaFlag; 77 break; 78 case SCRIPT_TAG('H', 'r', 'k', 't'): 79 subScriptBits = kKatakanaFlag | kHiraganaFlag; 80 break; 81 case SCRIPT_TAG('J', 'p', 'a', 'n'): 82 subScriptBits = kHanFlag | kKatakanaFlag | kHiraganaFlag; 83 break; 84 case SCRIPT_TAG('K', 'a', 'n', 'a'): 85 subScriptBits = kKatakanaFlag; 86 break; 87 case SCRIPT_TAG('K', 'o', 'r', 'e'): 88 subScriptBits = kHanFlag | kHangulFlag; 89 break; 90 case SCRIPT_TAG('Q', 'a', 'a', 'e'): 91 subScriptBits = kEmojiFlag; 92 break; 93 } 94 return subScriptBits; 95} 96 97std::string FontLanguage::getString() const { 98 if (mLanguage == 0ul) { 99 return "und"; 100 } 101 char buf[16]; 102 size_t i = 0; 103 buf[i++] = mLanguage & 0xFF ; 104 buf[i++] = (mLanguage >> 8) & 0xFF; 105 char third_letter = (mLanguage >> 16) & 0xFF; 106 if (third_letter != 0) buf[i++] = third_letter; 107 if (mScript != 0) { 108 buf[i++] = '-'; 109 buf[i++] = (mScript >> 24) & 0xFFu; 110 buf[i++] = (mScript >> 16) & 0xFFu; 111 buf[i++] = (mScript >> 8) & 0xFFu; 112 buf[i++] = mScript & 0xFFu; 113 } 114 return std::string(buf, i); 115} 116 117bool FontLanguage::isEqualScript(const FontLanguage other) const { 118 return other.mScript == mScript; 119} 120 121bool FontLanguage::supportsHbScript(hb_script_t script) const { 122 static_assert(SCRIPT_TAG('J', 'p', 'a', 'n') == HB_TAG('J', 'p', 'a', 'n'), 123 "The Minikin script and HarfBuzz hb_script_t have different encodings."); 124 if (script == mScript) return true; 125 uint8_t requestedBits = scriptToSubScriptBits(script); 126 return requestedBits != 0 && (mSubScriptBits & requestedBits) == requestedBits; 127} 128 129int FontLanguage::match(const FontLanguage other) const { 130 // TODO: Use script for matching. 131 return *this == other; 132} 133 134#undef SCRIPT_TAG 135} // namespace android 136