1 /*
2 * Copyright (c) 2023 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_parser.h"
17
18 #include <codecvt>
19 #include <dirent.h>
20 #include <iostream>
21 #include <iomanip>
22 #include <securec.h>
23 #ifdef BUILD_NON_SDK_VER
24 #include <iconv.h>
25 #endif
26
27 #include "font_config.h"
28 #include "texgine/utils/exlog.h"
29
30 namespace OHOS {
31 namespace Rosen {
32 namespace TextEngine {
33 #define SUCCESSED 0
34 #define FAILED 1
35
36 #define FONT_CONFIG_FILE "/system/fonts/visibility_list.json"
37 #define SYSTEM_FONT_PATH "/system/fonts/"
38
39 #define HALF(a) ((a) / 2)
40
41 // "weight" and "italic" will assigned value 0 and 1, -1 used to exclude unassigned
FontDescriptor()42 FontParser::FontDescriptor::FontDescriptor(): path(""), postScriptName(""), fullName(""),
43 fontFamily(""), fontSubfamily(""), postScriptNameLid(0), fullNameLid(0), fontFamilyLid(0),
44 fontSubfamilyLid(0), requestedLid(0), weight(-1), width(0), italic(-1), monoSpace(0), symbolic(0)
45 {
46 }
47
FontParser()48 FontParser::FontParser()
49 {
50 data_ = nullptr;
51 length_ = 0;
52 FontConfig fontConfig(FONT_CONFIG_FILE);
53 fontSet_ = fontConfig.GetFontSet();
54 }
55
ProcessCmapTable(const struct CmapTables * cmapTable,FontParser::FontDescriptor & fontDescriptor)56 void FontParser::ProcessCmapTable(const struct CmapTables* cmapTable, FontParser::FontDescriptor& fontDescriptor)
57 {
58 for (auto i = 0; i < cmapTable->numTables.Get(); ++i) {
59 const auto& record = cmapTable->encodingRecords[i];
60 FontParser::PlatformId platformId = static_cast<FontParser::PlatformId>(record.platformID.Get());
61 FontParser::EncodingIdWin encodingId = static_cast<FontParser::EncodingIdWin>(record.encodingID.Get());
62 if (platformId == FontParser::PlatformId::WINDOWS && encodingId == FontParser::EncodingIdWin::SYMBOL) {
63 fontDescriptor.symbolic = true;
64 break;
65 }
66 }
67 }
68
GetStringFromNameId(FontParser::NameId nameId,unsigned int languageId,const std::string & nameString,FontParser::FontDescriptor & fontDescriptor)69 void FontParser::GetStringFromNameId(FontParser::NameId nameId, unsigned int languageId, const std::string& nameString,
70 FontParser::FontDescriptor& fontDescriptor)
71 {
72 switch (nameId) {
73 case FontParser::NameId::FONT_FAMILY: {
74 SetNameString(fontDescriptor, fontDescriptor.fontFamily, fontDescriptor.fontFamilyLid,
75 languageId, nameString);
76 break;
77 }
78 case FontParser::NameId::FONT_SUBFAMILY: {
79 SetNameString(fontDescriptor, fontDescriptor.fontSubfamily, fontDescriptor.fontSubfamilyLid,
80 languageId, nameString);
81 break;
82 }
83 case FontParser::NameId::FULL_NAME: {
84 SetNameString(fontDescriptor, fontDescriptor.fullName, fontDescriptor.fullNameLid,
85 languageId, nameString);
86 break;
87 }
88 case FontParser::NameId::POSTSCRIPT_NAME: {
89 SetNameString(fontDescriptor, fontDescriptor.postScriptName, fontDescriptor.postScriptNameLid,
90 languageId, nameString);
91 break;
92 }
93 default: {
94 break;
95 }
96 }
97 }
98
SetNameString(FontParser::FontDescriptor & fontDescriptor,std::string & field,unsigned int & fieldLid,unsigned int languageId,const std::string & nameString)99 void FontParser::SetNameString(FontParser::FontDescriptor& fontDescriptor, std::string& field, unsigned int& fieldLid,
100 unsigned int languageId, const std::string& nameString)
101 {
102 bool willSet = field.empty();
103 if (!willSet) {
104 if (languageId == fontDescriptor.requestedLid) {
105 willSet = true;
106 } else if (fieldLid != fontDescriptor.requestedLid && languageId == LANGUAGE_DEFAULT) {
107 willSet = true;
108 }
109 }
110
111 if (willSet) {
112 fieldLid = languageId;
113 field = nameString;
114 }
115 }
116
ProcessNameTable(const struct NameTable * nameTable,FontParser::FontDescriptor & fontDescriptor) const117 int FontParser::ProcessNameTable(const struct NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor) const
118 {
119 auto count = nameTable->count.Get();
120 auto storageOffset = nameTable->storageOffset.Get();
121 auto stringStorage = data_ + storageOffset;
122 for (int i = 0; i < count; ++i) {
123 if (nameTable->nameRecord[i].stringOffset.Get() == 0 || nameTable->nameRecord[i].length.Get() == 0) {
124 continue;
125 }
126 FontParser::NameId nameId = static_cast<FontParser::NameId>(nameTable->nameRecord[i].nameId.Get());
127 unsigned int languageId = static_cast<unsigned int>(nameTable->nameRecord[i].languageId.Get());
128 FontParser::PlatformId platformId =
129 static_cast<FontParser::PlatformId>(nameTable->nameRecord[i].platformId.Get());
130 auto len = nameTable->nameRecord[i].length.Get();
131 auto stringOffset = nameTable->nameRecord[i].stringOffset.Get();
132 const char* data = stringStorage + stringOffset;
133 if (platformId == FontParser::PlatformId::MACINTOSH) {
134 #ifdef BUILD_NON_SDK_VER
135 std::string nameString = ToUtf8(std::string(data, len));
136 #else
137 std::string nameString(data, len);
138 #endif
139 GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
140 } else if (platformId == FontParser::PlatformId::WINDOWS) {
141 std::wstring_convert<std::codecvt_utf16<char16_t>, char16_t> converter;
142 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converterUtf8;
143 const std::u16string u16str = converter.from_bytes(data, data + len);
144 std::string nameString = converterUtf8.to_bytes(u16str);
145 GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
146 }
147 }
148
149 return SUCCESSED;
150 }
151
ProcessPostTable(const struct PostTable * postTable,FontParser::FontDescriptor & fontDescriptor)152 void FontParser::ProcessPostTable(const struct PostTable* postTable, FontParser::FontDescriptor& fontDescriptor)
153 {
154 if (postTable->italicAngle.Get() != 0) {
155 fontDescriptor.italic = 1; // means support italics
156 } else {
157 fontDescriptor.italic = 0;
158 }
159 if (postTable->isFixedPitch.Get() == 1) {
160 fontDescriptor.monoSpace = true;
161 }
162 }
163
ParseCmapTable(std::shared_ptr<TexgineTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)164 int FontParser::ParseCmapTable(std::shared_ptr<TexgineTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
165 {
166 auto tag = HB_TAG('c', 'm', 'a', 'p');
167 auto size = typeface->GetTableSize(tag);
168 if (size <= 0) {
169 LOGSO_FUNC_LINE(ERROR) << "haven't cmap";
170 return FAILED;
171 }
172 std::unique_ptr<char[]> tableData = nullptr;
173 tableData = std::make_unique<char[]>(size);
174 auto retTableData = typeface->GetTableData(tag, 0, size, tableData.get());
175 if (size != retTableData) {
176 LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
177 return FAILED;
178 }
179 hb_blob_t* hblob = nullptr;
180 hblob = hb_blob_create(
181 reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
182 if (hblob == nullptr) {
183 LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
184 return FAILED;
185 }
186 data_ = hb_blob_get_data(hblob, nullptr);
187 length_ = hb_blob_get_length(hblob);
188 auto parseCmap = std::make_shared<CmapTableParser>(data_, length_);
189 auto cmapTable = parseCmap->Parse(data_, length_);
190 ProcessCmapTable(cmapTable, fontDescriptor);
191
192 return SUCCESSED;
193 }
194
ParseNameTable(std::shared_ptr<TexgineTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)195 int FontParser::ParseNameTable(std::shared_ptr<TexgineTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
196 {
197 auto tag = HB_TAG('n', 'a', 'm', 'e');
198 auto size = typeface->GetTableSize(tag);
199 if (size <= 0) {
200 LOGSO_FUNC_LINE(ERROR) << "haven't name";
201 return FAILED;
202 }
203 std::unique_ptr<char[]> tableData = nullptr;
204 tableData = std::make_unique<char[]>(size);
205 auto retTableData = typeface->GetTableData(tag, 0, size, tableData.get());
206 if (size != retTableData) {
207 LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
208 return FAILED;
209 }
210 hb_blob_t* hblob = nullptr;
211 hblob = hb_blob_create(
212 reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
213 if (hblob == nullptr) {
214 LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
215 return FAILED;
216 }
217 data_ = hb_blob_get_data(hblob, nullptr);
218 length_ = hb_blob_get_length(hblob);
219 auto parseName = std::make_shared<NameTableParser>(data_, length_);
220 auto nameTable = parseName->Parse(data_, length_);
221 int ret = ProcessNameTable(nameTable, fontDescriptor);
222 if (ret != SUCCESSED) {
223 LOGSO_FUNC_LINE(ERROR) << "process name table failed";
224 return FAILED;
225 }
226
227 return SUCCESSED;
228 }
229
ParsePostTable(std::shared_ptr<TexgineTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)230 int FontParser::ParsePostTable(std::shared_ptr<TexgineTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
231 {
232 auto tag = HB_TAG('p', 'o', 's', 't');
233 auto size = typeface->GetTableSize(tag);
234 if (size <= 0) {
235 LOGSO_FUNC_LINE(ERROR) << "haven't post";
236 return FAILED;
237 }
238 std::unique_ptr<char[]> tableData = nullptr;
239 tableData = std::make_unique<char[]>(size);
240 auto retTableData = typeface->GetTableData(tag, 0, size, tableData.get());
241 if (size != retTableData) {
242 LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
243 return FAILED;
244 }
245 hb_blob_t* hblob = nullptr;
246 hblob = hb_blob_create(
247 reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
248 if (hblob == nullptr) {
249 LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
250 return FAILED;
251 }
252 data_ = hb_blob_get_data(hblob, nullptr);
253 length_ = hb_blob_get_length(hblob);
254 auto parsePost = std::make_shared<PostTableParser>(data_, length_);
255 auto postTable = parsePost->Parse(data_, length_);
256 ProcessPostTable(postTable, fontDescriptor);
257
258 return SUCCESSED;
259 }
260
ParseTable(std::shared_ptr<TexgineTypeface> typeface,FontParser::FontDescriptor & fontDescriptor)261 int FontParser::ParseTable(std::shared_ptr<TexgineTypeface> typeface, FontParser::FontDescriptor& fontDescriptor)
262 {
263 if (ParseCmapTable(typeface, fontDescriptor) != SUCCESSED) {
264 LOGSO_FUNC_LINE(ERROR) << "parse cmap failed";
265 return FAILED;
266 }
267 if (ParseNameTable(typeface, fontDescriptor) != SUCCESSED) {
268 LOGSO_FUNC_LINE(ERROR) << "parse name failed";
269 return FAILED;
270 }
271 if (ParsePostTable(typeface, fontDescriptor) != SUCCESSED) {
272 LOGSO_FUNC_LINE(ERROR) << "parse post failed";
273 return FAILED;
274 }
275
276 return SUCCESSED;
277 }
278
SetFontDescriptor(const unsigned int languageId)279 int FontParser::SetFontDescriptor(const unsigned int languageId)
280 {
281 for (unsigned int i = 0; i < fontSet_.size(); ++i) {
282 FontParser::FontDescriptor fontDescriptor;
283 fontDescriptor.requestedLid = languageId;
284 fontDescriptor.path = fontSet_[i];
285 const char* path = fontSet_[i].c_str();
286 auto typeface = TexgineTypeface::MakeFromFile(path);
287 if (typeface == nullptr) {
288 LOGSO_FUNC_LINE(ERROR) << "typeface is nullptr, can not parse: " << fontDescriptor.path;
289 continue;
290 }
291 auto fontStyle = typeface->GetFontStyle();
292 if (fontStyle == nullptr) {
293 LOGSO_FUNC_LINE(ERROR) << "fontStyle is nullptr, can not parse: " << fontDescriptor.path;
294 continue;
295 }
296 fontDescriptor.weight = fontStyle->GetWeight();
297 fontDescriptor.width = fontStyle->GetWidth();
298 if (ParseTable(typeface, fontDescriptor) != SUCCESSED) {
299 LOGSO_FUNC_LINE(ERROR) << "parse table failed";
300 return FAILED;
301 }
302 visibilityFonts_.emplace_back(fontDescriptor);
303 }
304
305 return SUCCESSED;
306 }
307
308 #ifdef BUILD_NON_SDK_VER
ToUtf8(const std::string & str)309 std::string FontParser::ToUtf8(const std::string& str)
310 {
311 std::string utf8Str;
312 // UTF-8 and GB2312 is encoding format of string
313 iconv_t conv = iconv_open("UTF-8", "GB2312");
314 if (conv == (iconv_t)-1) {
315 return utf8Str;
316 }
317 char* inBuf = const_cast<char*>(str.c_str());
318 size_t inBytesLeft = str.length();
319 size_t outBytesLeft = inBytesLeft * 2;
320 char* outBuf = new char[outBytesLeft];
321 char* outBufStart = outBuf;
322 size_t res = iconv(conv, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft);
323 if (res != (size_t)-1) {
324 utf8Str.assign(outBufStart, outBuf - outBufStart);
325 }
326 delete[] outBufStart;
327 iconv_close(conv);
328 return utf8Str;
329 }
330 #endif
331
GetVisibilityFonts(const std::string locale)332 std::vector<FontParser::FontDescriptor> FontParser::GetVisibilityFonts(const std::string locale)
333 {
334 if (SetFontDescriptor(GetLanguageId(locale)) != SUCCESSED) {
335 LOGSO_FUNC_LINE(ERROR) << "set visibility font descriptor failed";
336 }
337
338 return visibilityFonts_;
339 }
340
341 class SystemFont {
342 public:
SystemFont(const char * fPath=SYSTEM_FONT_PATH)343 SystemFont(const char* fPath = SYSTEM_FONT_PATH)
344 {
345 ParseConfig(fPath);
346 }
347
348 ~SystemFont() = default;
349
GetSystemFontSet() const350 std::shared_ptr<std::vector<std::string>> GetSystemFontSet() const
351 {
352 return systemFontSet_;
353 }
354
355 private:
ParseConfig(const char * fPath)356 void ParseConfig(const char* fPath)
357 {
358 if (fPath == nullptr) {
359 return;
360 }
361 systemFontSet_ = std::make_shared<std::vector<std::string>>();
362 DIR *dir = opendir(fPath);
363 if (dir == nullptr) {
364 return;
365 }
366 struct dirent *entry;
367 while ((entry = readdir(dir)) != nullptr) {
368 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
369 continue;
370 }
371 std::string tmp = entry->d_name;
372 systemFontSet_->push_back(SYSTEM_FONT_PATH + tmp);
373 }
374 closedir(dir);
375 }
376
377 std::shared_ptr<std::vector<std::string>> systemFontSet_;
378 };
379
ParseFontDescriptor(const std::string & fontName,const unsigned int languageId)380 std::unique_ptr<FontParser::FontDescriptor> FontParser::ParseFontDescriptor(const std::string& fontName,
381 const unsigned int languageId)
382 {
383 SystemFont sSystemFont;
384 std::shared_ptr<std::vector<std::string>> systemFontList = sSystemFont.GetSystemFontSet();
385 if (systemFontList == nullptr || systemFontList->empty()) {
386 return nullptr;
387 }
388
389 int systemFontSize = systemFontList->size();
390 for (auto font : fontSet_) {
391 for (int i = 0; i < systemFontSize; i++) {
392 if (systemFontSize <= 0) {
393 break;
394 }
395 if ((*systemFontList)[i] == font) {
396 systemFontList->erase(systemFontList->begin() + i);
397 systemFontSize --;
398 break;
399 }
400 }
401
402 systemFontList->push_back(font);
403 }
404
405 for (int i = systemFontList->size() - 1; i >= 0; --i) {
406 FontParser::FontDescriptor fontDescriptor;
407 fontDescriptor.requestedLid = languageId;
408 fontDescriptor.path = (*systemFontList)[i];
409 const char* path = (*systemFontList)[i].c_str();
410 auto typeface = TexgineTypeface::MakeFromFile(path);
411 if (typeface == nullptr) {
412 LOGSO_FUNC_LINE(ERROR) << "typeface is nullptr, can not parse: " << fontDescriptor.path;
413 continue;
414 }
415 auto fontStyle = typeface->GetFontStyle();
416 if (fontStyle == nullptr) {
417 LOGSO_FUNC_LINE(ERROR) << "fontStyle is nullptr, can not parse: " << fontDescriptor.path;
418 continue;
419 }
420 fontDescriptor.weight = fontStyle->GetWeight();
421 fontDescriptor.width = fontStyle->GetWidth();
422 if (ParseTable(typeface, fontDescriptor) != SUCCESSED) {
423 LOGSO_FUNC_LINE(ERROR) << "parse table failed";
424 return nullptr;
425 }
426 std::string name = SYSTEM_FONT_PATH + fontName;
427 if (fontDescriptor.fullName == fontName || fontDescriptor.path == name) {
428 return std::make_unique<FontDescriptor>(fontDescriptor);
429 }
430 }
431
432 return nullptr;
433 }
434
GetVisibilityFontByName(const std::string & fontName,const std::string locale)435 std::unique_ptr<FontParser::FontDescriptor> FontParser::GetVisibilityFontByName(const std::string& fontName,
436 const std::string locale)
437 {
438 return ParseFontDescriptor(fontName, GetLanguageId(locale));
439 }
440 } // namespace TextEngine
441 } // namespace Rosen
442 } // namespace OHOS
443