1 /* 2 * Copyright (C) 2017 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 #include "HyphenatorMap.h" 18 19 #include "LocaleListCache.h" 20 #include "MinikinInternal.h" 21 22 namespace minikin { 23 24 namespace { 25 constexpr SubtagBits LANGUAGE = SubtagBits::LANGUAGE; 26 constexpr SubtagBits SCRIPT = SubtagBits::SCRIPT; 27 constexpr SubtagBits REGION = SubtagBits::REGION; 28 constexpr SubtagBits VARIANT = SubtagBits::VARIANT; 29 30 constexpr int DEFAULT_MIN_PREFIX = 2; 31 constexpr int DEFAULT_MAX_PREFIX = 2; 32 } // namespace 33 34 // Following two function's implementations are here since Hyphenator.cpp can't include 35 // HyphenatorMap.h due to harfbuzz dependency on the host binary. 36 void addHyphenator(const std::string& localeStr, const Hyphenator* hyphenator) { 37 HyphenatorMap::add(localeStr, hyphenator); 38 } 39 40 void addHyphenatorAlias(const std::string& fromLocaleStr, const std::string& toLocaleStr) { 41 HyphenatorMap::addAlias(fromLocaleStr, toLocaleStr); 42 } 43 44 HyphenatorMap::HyphenatorMap() 45 : mSoftHyphenOnlyHyphenator( 46 Hyphenator::loadBinary(nullptr, DEFAULT_MIN_PREFIX, DEFAULT_MAX_PREFIX, "")) {} 47 48 void HyphenatorMap::addInternal(const std::string& localeStr, const Hyphenator* hyphenator) { 49 const Locale locale(localeStr); 50 std::lock_guard<std::mutex> lock(mMutex); 51 // Overwrite even if there is already a fallback entry. 52 mMap[locale.getIdentifier()] = hyphenator; 53 } 54 55 void HyphenatorMap::clearInternal() { 56 std::lock_guard<std::mutex> lock(mMutex); 57 mMap.clear(); 58 } 59 void HyphenatorMap::addAliasInternal(const std::string& fromLocaleStr, 60 const std::string& toLocaleStr) { 61 const Locale fromLocale(fromLocaleStr); 62 const Locale toLocale(toLocaleStr); 63 std::lock_guard<std::mutex> lock(mMutex); 64 auto it = mMap.find(toLocale.getIdentifier()); 65 if (it == mMap.end()) { 66 ALOGE("Target Hyphenator not found."); 67 return; 68 } 69 // Overwrite even if there is already a fallback entry. 70 mMap[fromLocale.getIdentifier()] = it->second; 71 } 72 73 const Hyphenator* HyphenatorMap::lookupInternal(const Locale& locale) { 74 const uint64_t id = locale.getIdentifier(); 75 std::lock_guard<std::mutex> lock(mMutex); 76 const Hyphenator* result = lookupByIdentifier(id); 77 if (result != nullptr) { 78 return result; // Found with exact match. 79 } 80 81 // First, try with dropping emoji extensions. 82 result = lookupBySubtag(locale, LANGUAGE | REGION | SCRIPT | VARIANT); 83 if (result != nullptr) { 84 goto insert_result_and_return; 85 } 86 // If not found, try with dropping script. 87 result = lookupBySubtag(locale, LANGUAGE | REGION | VARIANT); 88 if (result != nullptr) { 89 goto insert_result_and_return; 90 } 91 // If not found, try with dropping script and region code. 92 result = lookupBySubtag(locale, LANGUAGE | VARIANT); 93 if (result != nullptr) { 94 goto insert_result_and_return; 95 } 96 // If not found, try only with language code. 97 result = lookupBySubtag(locale, LANGUAGE); 98 if (result != nullptr) { 99 goto insert_result_and_return; 100 } 101 // Still not found, try only with script. 102 result = lookupBySubtag(locale, SCRIPT); 103 if (result != nullptr) { 104 goto insert_result_and_return; 105 } 106 107 // If not found, use soft hyphen only hyphenator. 108 result = mSoftHyphenOnlyHyphenator; 109 110 insert_result_and_return: 111 mMap.insert(std::make_pair(id, result)); 112 return result; 113 } 114 115 const Hyphenator* HyphenatorMap::lookupByIdentifier(uint64_t id) const { 116 auto it = mMap.find(id); 117 return it == mMap.end() ? nullptr : it->second; 118 } 119 120 const Hyphenator* HyphenatorMap::lookupBySubtag(const Locale& locale, SubtagBits bits) const { 121 const Locale partialLocale = locale.getPartialLocale(bits); 122 if (!partialLocale.isSupported() || partialLocale == locale) { 123 return nullptr; // Skip the partial locale result in the same locale or not supported. 124 } 125 return lookupByIdentifier(partialLocale.getIdentifier()); 126 } 127 128 } // namespace minikin 129