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 #include "font/ui_multi_font_manager.h"
17 #include "common/typed_text.h"
18 #include "font/ui_font.h"
19 
20 #include "gfx_utils/mem_api.h"
21 #include "securec.h"
22 #if ENABLE_SHAPING
23 #include "font/ui_text_shaping.h"
24 #endif
25 #if ENABLE_MULTI_FONT
26 namespace OHOS {
UIMultiFontManager()27 UIMultiFontManager::UIMultiFontManager()
28     : arbicTtfId_(0), thaiTtfId_(0), myanmarTtfId_(0),
29       devanagariTtfId_(0), hebrewTtfId_(0),
30       bengaliTtfId_(0), topIndex_(0)
31 {
32     const UITextLanguageFontParam* fontParam = nullptr;
33     uint16_t totalFontId = UIFontBuilder::GetInstance()->GetTotalFontId();
34     for (uint16_t i = 0; i < totalFontId; i++) {
35         fontParam = UIFont::GetInstance()->GetFontInfo(i);
36         if (fontParam == nullptr) {
37             continue;
38         }
39         if (!fontParam->shaping) {
40             continue;
41         }
42         if (strstr(fontParam->ttfName, ARABIC_LANG) != nullptr) {
43             arbicTtfId_ = fontParam->ttfId;
44         } else if (strstr(fontParam->ttfName, THAI_LANG) != nullptr) {
45             thaiTtfId_ = fontParam->ttfId;
46         } else if (strstr(fontParam->ttfName, MYAN_LANG) != nullptr) {
47             myanmarTtfId_ = fontParam->ttfId;
48         } else if (strstr(fontParam->ttfName, DVCARI_LANG) != nullptr) {
49             devanagariTtfId_ = fontParam->ttfId;
50         } else if (strstr(fontParam->ttfName, HBREW_LANG) != nullptr) {
51             hebrewTtfId_ = fontParam->ttfId;
52         } else if (strstr(fontParam->ttfName, BENGALI_LANG) != nullptr) {
53             bengaliTtfId_ = fontParam->ttfId;
54         }
55     }
56     fontIdIndex_ = static_cast<uint8_t*>(UIMalloc(totalFontId));
57     if (fontIdIndex_ == nullptr) {
58         return;
59     }
60     for (uint16_t index = 0; index < totalFontId; index++) {
61         fontIdIndex_[index] = MAX_FONT_SEARCH_NUM;
62     }
63     for (uint8_t index = 0; index < MAX_FONT_SEARCH_NUM; index++) {
64         fontNodes_[index].fontIds = nullptr;
65         fontNodes_[index].size = 0;
66     }
67 }
68 
~UIMultiFontManager()69 UIMultiFontManager::~UIMultiFontManager()
70 {
71     UIFree(fontIdIndex_);
72     fontIdIndex_ = nullptr;
73 }
74 
AddNewFont(uint16_t fontListId,uint16_t * fontIds,int8_t size,uint8_t fontIndex)75 int8_t UIMultiFontManager::AddNewFont(uint16_t fontListId, uint16_t* fontIds, int8_t size, uint8_t fontIndex)
76 {
77     fontNodes_[fontIndex].fontIds = static_cast<uint16_t*>(UIMalloc(size * sizeof(uint16_t)));
78     if (fontNodes_[fontIndex].fontIds == nullptr) {
79         return fontIndex;
80     }
81     fontIdIndex_[fontListId] = fontIndex;
82     (void)memcpy_s(fontNodes_[fontIndex].fontIds, size * sizeof(uint16_t), fontIds, size * sizeof(uint16_t));
83     fontNodes_[fontIndex].size = size;
84     return fontIndex + 1;
85 }
86 
UpdateFont(uint16_t fontListId,uint16_t * fontIds,uint8_t size)87 int8_t UIMultiFontManager::UpdateFont(uint16_t fontListId, uint16_t* fontIds, uint8_t size)
88 {
89     uint8_t index = fontIdIndex_[fontListId];
90     if (index < topIndex_) {
91         UIFree(fontNodes_[index].fontIds);
92         fontNodes_[index].fontIds = nullptr;
93     } else {
94         index = topIndex_;
95     }
96 
97     uint8_t nextIndex = AddNewFont(fontListId, fontIds, size, index);
98     if (topIndex_ < nextIndex) {
99         topIndex_ = nextIndex;
100     }
101     return (fontNodes_[index].fontIds == nullptr) ? INVALID_RET_VALUE : RET_VALUE_OK;
102 }
103 
UpdateScript(UITextLanguageFontParam & fonts)104 void UIMultiFontManager::UpdateScript(UITextLanguageFontParam& fonts)
105 {
106     if (strstr(fonts.ttfName, ARABIC_LANG) != nullptr) {
107         arbicTtfId_ = fonts.ttfId;
108     } else if (strstr(fonts.ttfName, THAI_LANG) != nullptr) {
109         thaiTtfId_ = fonts.ttfId;
110     } else if (strstr(fonts.ttfName, MYAN_LANG) != nullptr) {
111         myanmarTtfId_ = fonts.ttfId;
112     } else if (strstr(fonts.ttfName, DVCARI_LANG) != nullptr) {
113         devanagariTtfId_ = fonts.ttfId;
114     } else if (strstr(fonts.ttfName, HBREW_LANG) != nullptr) {
115         hebrewTtfId_ = fonts.ttfId;
116     } else if (strstr(fonts.ttfName, BENGALI_LANG) != nullptr) {
117         bengaliTtfId_ = fonts.ttfId;
118     }
119 }
120 
GetInstance()121 UIMultiFontManager* UIMultiFontManager::GetInstance()
122 {
123     static UIMultiFontManager instance;
124     return &instance;
125 }
126 
ClearSearchFontList()127 void UIMultiFontManager::ClearSearchFontList()
128 {
129     uint16_t totalFontId = UIFontBuilder::GetInstance()->GetTotalFontId();
130     for (uint16_t index = 0; index < totalFontId; index++) {
131         fontIdIndex_[index] = MAX_FONT_SEARCH_NUM;
132     }
133 
134     for (auto &node : fontNodes_) {
135         UIFree(node.fontIds);
136         node.fontIds = nullptr;
137         node.size = 0;
138     }
139     topIndex_ = 0;
140 }
141 
SetSearchFontList(uint16_t fontListId,uint16_t * fontIds,uint8_t size)142 int8_t UIMultiFontManager::SetSearchFontList(uint16_t fontListId, uint16_t* fontIds, uint8_t size)
143 {
144     if ((fontListId >= UIFontBuilder::GetInstance()->GetTotalFontId()) || (fontIds == nullptr) || (size == 0) ||
145         (fontIdIndex_ == nullptr) || (topIndex_ >= MAX_FONT_SEARCH_NUM)) {
146         return INVALID_RET_VALUE;
147     }
148     // update
149     return UpdateFont(fontListId, fontIds, size);
150 }
151 
GetSearchFontList(uint16_t fontListId,uint16_t ** fontIds)152 int32_t UIMultiFontManager::GetSearchFontList(uint16_t fontListId, uint16_t** fontIds)
153 {
154     if ((fontListId >= UIFontBuilder::GetInstance()->GetTotalFontId()) || (fontIds == nullptr) ||
155         (fontIdIndex_ == nullptr) || (fontIdIndex_[fontListId] >= MAX_FONT_SEARCH_NUM)) {
156         return static_cast<uint32_t>(INVALID_RET_VALUE);
157     }
158     *fontIds = fontNodes_[fontIdIndex_[fontListId]].fontIds;
159     return static_cast<uint32_t>(fontNodes_[fontIdIndex_[fontListId]].size);
160 }
161 
IsNeedShaping(const char * text,uint8_t & ttfId,uint32_t & script)162 bool UIMultiFontManager::IsNeedShaping(const char *text, uint8_t &ttfId, uint32_t &script)
163 {
164     if (text == nullptr) {
165         return false;
166     }
167 
168     uint32_t i = 0;
169     while (text[i] != '\0') {
170         uint32_t unicode = TypedText::GetUTF8Next(text, i, i);
171         if (IsShapingLetter(unicode, ttfId)) {
172 #if ENABLE_SHAPING
173             script = GetScriptByTtfId(ttfId);
174 #endif
175             return true;
176         }
177     }
178     return false;
179 }
180 
GetShapingFontId(const char * text,uint16_t fontId,uint8_t & ttfId,uint32_t & script)181 uint16_t UIMultiFontManager::GetShapingFontId(const char* text, uint16_t fontId, uint8_t& ttfId, uint32_t& script)
182 {
183     // the shaping font is in search list, then shapingFontId_ store the real shaping fontid
184     UIFont* fontEngine = UIFont::GetInstance();
185     const UITextLanguageFontParam* fontParam1 = fontEngine->GetFontInfo(fontId);
186     if (fontParam1 == nullptr) {
187         return DEFAULT_SHAPING_ID;
188     }
189     if (!fontParam1->shaping) {
190         if (!IsNeedShaping(text, ttfId, script)) {
191             return 0; // 0 means  no need to shape
192         }
193         uint16_t* searchLists = nullptr;
194         int32_t length = GetSearchFontList(fontId, &searchLists);
195         const UITextLanguageFontParam* fontParam2 = nullptr;
196         for (uint16_t i = 0; i < length; i++) {
197             fontParam2 = fontEngine->GetFontInfo(searchLists[i]);
198             if (fontParam2 == nullptr) {
199                 continue;
200             }
201             if (fontParam2->ttfId == ttfId) {
202                 return searchLists[i];
203             }
204         }
205         return 0;
206     }
207     ttfId = fontParam1->ttfId;
208 
209 #if ENABLE_SHAPING
210     script = GetScriptByTtfId(ttfId);
211 #endif
212     return DEFAULT_SHAPING_ID;
213 }
IsShapingLetter(uint32_t unicode,uint8_t & ttfId)214 int8_t UIMultiFontManager::IsShapingLetter(uint32_t unicode, uint8_t &ttfId)
215 {
216     // arbic
217     if ((unicode <= 0x06FF) && (unicode >= 0x0600)) {
218         ttfId = arbicTtfId_;
219         return ttfId != 0;
220     }
221     // thai
222     if ((unicode <= 0x0E7F) && (unicode >= 0x0E00)) {
223         ttfId = thaiTtfId_;
224         return ttfId != 0;
225     }
226     // Devanagari
227     if ((unicode <= 0x097F) && (unicode >= 0x0900)) {
228         ttfId = devanagariTtfId_;
229         return ttfId != 0;
230     }
231     // Hebrew
232     if ((unicode <= 0x05FF) && (unicode >= 0x0590)) {
233         ttfId = hebrewTtfId_;
234         return ttfId != 0;
235     }
236     // Myanmar
237     if ((unicode <= 0x109F) && (unicode >= 0x1000)) {
238         ttfId = myanmarTtfId_;
239         return ttfId != 0;
240     }
241     // Bengali
242     if ((unicode <= 0x9FF) && (unicode >= 0x980)) {
243         ttfId = bengaliTtfId_;
244         return ttfId != 0;
245     }
246     return false;
247 }
248 #if ENABLE_SHAPING
GetScriptByTtfId(uint8_t ttfId)249 uint32_t UIMultiFontManager::GetScriptByTtfId(uint8_t ttfId)
250 {
251     // arbic
252     if (ttfId == arbicTtfId_) {
253         return SHAPING_SCRIPT_ARABIC;
254     }
255     // thai
256     if (ttfId == thaiTtfId_) {
257         return SHAPING_SCRIPT_THAI;
258     }
259     // Devanagari
260     if (ttfId == devanagariTtfId_) {
261         return SHAPING_SCRIPT_DEVANAGARI;
262     }
263     // Hebrew
264     if (ttfId == hebrewTtfId_) {
265         return SHAPING_SCRIPT_HEBREW;
266     }
267     // Myanmar
268     if (ttfId == myanmarTtfId_) {
269         return SHAPING_SCRIPT_MYANMAR;
270     }
271     // Bengali
272     if (ttfId == bengaliTtfId_) {
273         return SHAPING_SCRIPT_BENGALI;
274     }
275     return SHAPING_SCRIPT_INVALID;
276 }
277 #endif
278 }
279 #endif
280