• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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