1 /*
2 * Copyright (c) 2020-2021 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 #if ENABLE_ICU
17 #include "font/ui_line_break.h"
18 #include "common/typed_text.h"
19 #include "font/ui_font.h"
20 #include "rbbidata.h"
21 #include "ucmndata.h"
22
23 using namespace U_ICU_NAMESPACE;
24 namespace OHOS {
MemAlloc(const void * context,size_t size)25 static void* MemAlloc(const void* context, size_t size)
26 {
27 return UIMalloc(size);
28 }
29
MemFree(const void * context,void * mem)30 static void MemFree(const void* context, void* mem)
31 {
32 if (mem == nullptr) {
33 return;
34 }
35 UIFree(mem);
36 }
37
MemRealloc(const void * context,void * mem,size_t size)38 static void* MemRealloc(const void* context, void* mem, size_t size)
39 {
40 return UIRealloc(mem, size);
41 }
42
GetInstance()43 UILineBreakEngine& UILineBreakEngine::GetInstance()
44 {
45 static UILineBreakEngine instance;
46 return instance;
47 }
48
GetNextBreakPos(UILineBreakProxy & record)49 uint16_t UILineBreakEngine::GetNextBreakPos(UILineBreakProxy& record)
50 {
51 const UChar* str = reinterpret_cast<const UChar*>(record.GetStr());
52 if ((str == nullptr) || !initSuccess_ || (lineBreakTrie_ == nullptr)) {
53 return 0;
54 }
55 int32_t state = LINE_BREAK_STATE_START;
56 const RBBIStateTable* rbbStateTable = reinterpret_cast<const RBBIStateTable*>(stateTbl_);
57 const RBBIStateTableRow* row =
58 reinterpret_cast<const RBBIStateTableRow*>(rbbStateTable->fTableData + rbbStateTable->fRowLen * state);
59 UTrie2* trie2 = reinterpret_cast<UTrie2*>(lineBreakTrie_);
60 for (uint16_t index = 0; index < record.GetStrLen(); ++index) {
61 uint16_t category = UTRIE2_GET16(trie2, static_cast<uint32_t>(str[index]));
62 // 0x4000: remove the dictionary flag bit
63 if ((category & 0x4000) != 0) {
64 // 0x4000: remove the dictionary flag bit
65 category &= ~0x4000;
66 }
67 state = row->fNextState[category];
68 row = reinterpret_cast<const RBBIStateTableRow*>(rbbStateTable->fTableData + rbbStateTable->fRowLen * state);
69 int16_t completedRule = row->fAccepting;
70 if ((completedRule > 0) || (state == LINE_BREAK_STATE_STOP)) {
71 return index;
72 }
73 }
74 return record.GetStrLen();
75 }
76
LoadRule()77 void UILineBreakEngine::LoadRule()
78 {
79 if ((fp_ < 0) || (addr_ == nullptr)) {
80 return;
81 }
82 UErrorCode status = U_ZERO_ERROR;
83 u_setMemoryFunctions(nullptr, MemAlloc, MemRealloc, MemFree, &status);
84 if (status != U_ZERO_ERROR) {
85 return;
86 }
87 int32_t ret = lseek(fp_, offset_, SEEK_SET);
88 if (ret != offset_) {
89 return;
90 }
91 char* buf = addr_;
92 ret = read(fp_, buf, size_);
93 if (ret != size_) {
94 return;
95 }
96 const char* dataInBytes = reinterpret_cast<const char*>(buf);
97 const DataHeader* dh = reinterpret_cast<const DataHeader*>(buf);
98 const RBBIDataHeader* rbbidh = reinterpret_cast<const RBBIDataHeader*>(dataInBytes + dh->dataHeader.headerSize);
99 stateTbl_ = reinterpret_cast<const RBBIStateTable*>(reinterpret_cast<const char*>(rbbidh) + rbbidh->fFTable);
100 status = U_ZERO_ERROR;
101 lineBreakTrie_ = reinterpret_cast<UTrie2*>(
102 utrie2_openFromSerialized(UTRIE2_16_VALUE_BITS, reinterpret_cast<const uint8_t*>(rbbidh) + rbbidh->fTrie,
103 rbbidh->fTrieLen, nullptr, &status));
104 if (status != U_ZERO_ERROR) {
105 return;
106 }
107 initSuccess_ = true;
108 }
109
GetNextLineAndWidth(const char * text,int16_t space,bool allBreak,int16_t & maxWidth,uint16_t len)110 uint32_t UILineBreakEngine::GetNextLineAndWidth(const char* text,
111 int16_t space,
112 bool allBreak,
113 int16_t& maxWidth,
114 uint16_t len)
115 {
116 if (text == nullptr) {
117 return 0;
118 }
119 bool isAllCanBreak = allBreak;
120 uint32_t byteIdx = 0;
121 uint32_t preIndex = 0;
122 int16_t lastWidth = 0;
123 int16_t lastIndex = 0;
124 int16_t curWidth = 0;
125 int32_t state = LINE_BREAK_STATE_START;
126 int16_t width = 0;
127 while ((text[byteIdx] != '\0') && (byteIdx < len)) {
128 uint32_t unicode = TypedText::GetUTF8Next(text, preIndex, byteIdx);
129 if (unicode == 0) {
130 preIndex = byteIdx;
131 continue;
132 }
133 if (isAllCanBreak || IsBreakPos(unicode, state)) {
134 state = LINE_BREAK_STATE_START;
135 // Accumulates the status value from the current character.
136 IsBreakPos(unicode, state);
137 lastIndex = preIndex;
138 lastWidth = curWidth;
139 }
140 width = UIFont::GetInstance()->GetWidth(unicode, 0);
141 int16_t nextWidth = (curWidth > 0 && width > 0) ? (curWidth + space + width) : (curWidth + width);
142 if (nextWidth > maxWidth) {
143 if (lastIndex == 0) {
144 break;
145 }
146 maxWidth = lastWidth;
147 return lastIndex;
148 }
149 curWidth = nextWidth;
150 preIndex = byteIdx;
151 if (byteIdx > 0 && ((text[byteIdx - 1] == '\r') || (text[byteIdx - 1] == '\n'))) {
152 break;
153 }
154 }
155 maxWidth = curWidth;
156 return preIndex;
157 }
158
IsBreakPos(uint32_t unicode,int32_t & state)159 bool UILineBreakEngine::IsBreakPos(uint32_t unicode, int32_t& state)
160 {
161 if ((unicode > TypedText::MAX_UINT16_HIGH_SCOPE) || (stateTbl_ == nullptr) || (lineBreakTrie_ == nullptr)) {
162 return true;
163 }
164 const RBBIStateTable* rbbStateTable = reinterpret_cast<const RBBIStateTable*>(stateTbl_);
165 const RBBIStateTableRow* row =
166 reinterpret_cast<const RBBIStateTableRow*>(rbbStateTable->fTableData + rbbStateTable->fRowLen * state);
167 uint16_t utf16 = 0;
168 if (unicode <= TypedText::MAX_UINT16_LOW_SCOPE) {
169 utf16 = (unicode & TypedText::MAX_UINT16_LOW_SCOPE);
170 } else if (unicode <= TypedText::MAX_UINT16_HIGH_SCOPE) {
171 utf16 = static_cast<uint16_t>(TypedText::UTF16_LOW_PARAM + (unicode & TypedText::UTF16_LOW_MASK)); // low
172 uint16_t category = UTRIE2_GET16(reinterpret_cast<UTrie2*>(lineBreakTrie_), static_cast<uint32_t>(utf16));
173 // 0x4000: remove the dictionary flag bit
174 if ((category & 0x4000) != 0) {
175 // 0x4000: remove the dictionary flag bit
176 category &= ~0x4000;
177 }
178 state = row->fNextState[category];
179 row = reinterpret_cast<const RBBIStateTableRow*>(rbbStateTable->fTableData + rbbStateTable->fRowLen * state);
180 utf16 = static_cast<uint16_t>(TypedText::UTF16_HIGH_PARAM1 + (unicode >> TypedText::UTF16_HIGH_SHIFT) -
181 TypedText::UTF16_HIGH_PARAM2); // high
182 }
183 uint16_t category = UTRIE2_GET16(reinterpret_cast<UTrie2*>(lineBreakTrie_), static_cast<uint32_t>(utf16));
184 // 0x4000: remove the dictionary flag bit
185 if ((category & 0x4000) != 0) {
186 // 0x4000: remove the dictionary flag bit
187 category &= ~0x4000;
188 }
189 state = row->fNextState[category];
190 row = reinterpret_cast<const RBBIStateTableRow*>(rbbStateTable->fTableData + rbbStateTable->fRowLen * state);
191 return (row->fAccepting > 0 || state == LINE_BREAK_STATE_STOP);
192 }
193 } // namespace OHOS
194 #endif // ENABLE_ICU
195