1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef THIRD_PARTY_SKIA_HYPHENATOR_H 17 #define THIRD_PARTY_SKIA_HYPHENATOR_H 18 19 #ifdef ENABLE_TEXT_ENHANCE 20 #include <atomic> 21 #include <cctype> 22 #include <cstring> 23 #include <memory> 24 #include <mutex> 25 #include <shared_mutex> 26 #include <ucase.h> 27 #include <map> 28 #include <vector> 29 30 #include "include/core/SkString.h" 31 #include "include/HyphenTrie.h" 32 33 namespace skia { 34 namespace textlayout { 35 constexpr size_t HYPHEN_WORD_SHIFT = 4; 36 constexpr size_t HYPHEN_BASE_CODE_SHIFT = 2; 37 constexpr size_t HYPHEN_SHIFT_BITS_14 = 14; 38 constexpr size_t HYPHEN_SHIFT_BITS_30 = 30; 39 40 enum class PathType : uint8_t { 41 PATTERN = 0, 42 LINEAR = 1, 43 PAIRS = 2, 44 DIRECT = 3 45 }; 46 47 struct Pattern { 48 uint8_t patterns[8]; // dynamic 49 }; 50 51 struct ArrayOf16bits { 52 uint16_t count; 53 uint16_t codes[3]; // dynamic 54 }; 55 56 struct HyphenatorHeader { 57 uint8_t magic1{0}; 58 uint8_t magic2{0}; 59 uint8_t minCp{0}; 60 uint8_t maxCp{0}; 61 uint32_t toc{0}; 62 uint32_t mappings{0}; 63 uint32_t version{0}; 64 65 uint16_t codeOffset(uint16_t code, const ArrayOf16bits* maps = nullptr) const 66 { 67 // need still reconsider what we want to do with a nodes in the middle of graph 68 if (maps != nullptr && (code < minCp || code > maxCp)) { 69 // we could assert that count is even 70 for (size_t i = maps->count; i != 0;) { 71 i -= HYPHEN_BASE_CODE_SHIFT; 72 if (maps->codes[i] == code) { 73 auto offset = maps->codes[i + 1]; 74 return (maxCp - minCp) * HYPHEN_BASE_CODE_SHIFT + (offset - maxCp) * HYPHEN_BASE_CODE_SHIFT + 1; 75 } 76 } 77 return maxCount(maps); 78 } 79 if (maps) { 80 // + 1 because previous end is before next start 81 // 2x because every second value to beginning addres 82 return (code - minCp) * HYPHEN_BASE_CODE_SHIFT + 1; 83 } else { 84 if (code < minCp || code > maxCp) { 85 return maxCp + 1; 86 } 87 return (code - minCp); 88 } 89 } 90 toLowerHyphenatorHeader91 inline static void toLower(uint16_t& code) 92 { 93 if (code == '.') { 94 code = '`'; 95 } else if (code == '\'') { 96 code = '^'; 97 } else if (code == '-') { 98 code = '_'; 99 } else { 100 // Open Harmony seems to have this even before C++20 101 code = ucase_tolower(code); 102 } 103 } 104 maxCountHyphenatorHeader105 inline uint16_t maxCount(const ArrayOf16bits* maps) const 106 { 107 // need to write this in binary provider !! 108 return (maxCp - minCp) * HYPHEN_BASE_CODE_SHIFT + maps->count; 109 } 110 }; 111 112 class Hyphenator { 113 public: getInstance()114 static Hyphenator& getInstance() 115 { 116 static Hyphenator instance; 117 std::call_once(initFlag, []() { instance.initTrieTree(); }); 118 return instance; 119 } 120 const std::vector<uint8_t>& getHyphenatorData(const std::string& locale); 121 std::vector<uint8_t> findBreakPositions(const SkString& locale, const SkString& text, 122 size_t startPos, size_t endPos); 123 124 private: 125 static std::once_flag initFlag; 126 Hyphenator() = default; 127 ~Hyphenator() = default; 128 Hyphenator(const Hyphenator&) = delete; 129 Hyphenator& operator=(const Hyphenator&) = delete; 130 131 void initTrieTree(); 132 const std::vector<uint8_t>& findHyphenatorData(const std::string& langCode); 133 const std::vector<uint8_t>& loadPatternFile(const std::string& langCode); 134 135 mutable std::shared_mutex mutex_; 136 std::map<std::string, std::vector<uint8_t>> fHyphenMap; 137 HyphenTrie fTrieTree; 138 const std::vector<uint8_t> fEmptyResult; 139 }; 140 } // namespace textlayout 141 } // namespace skia 142 #endif // ENABLE_TEXT_ENHANCE 143 #endif // THIRD_PARTY_SKIA_HYPHENATOR_H 144